2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2018 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 // vss.cpp -- Interface to Volume Shadow Copies (VSS)
22 // Copyright transferred from MATRIX-Computer GmbH to
23 // Kern Sibbald by express permission.
25 // Author : Thorsten Engel
26 // Created On : Fri May 06 21:44:00 2005
32 #include "filed/filed.h"
48 * Kludges to get Vista code to compile.
49 * by Kern Sibbald - June 2007
53 #define __RPC_unique_pointer
55 #ifndef __RPC__out_ecount_part
56 #define __RPC__out_ecount_part(x, y)
58 #define __RPC__deref_inout_opt
61 #if !defined(ENABLE_NLS)
62 #define setlocale(p, d)
66 // Used for safe string manipulation
71 class IXMLDOMDocument;
74 /* Reduce compiler warnings from Windows vss code */
79 #define VSSClientGeneric VSSClientXP
80 #include "inc/WinXP/vss.h"
81 #include "inc/WinXP/vswriter.h"
82 #include "inc/WinXP/vsbackup.h"
87 #define VSSClientGeneric VSSClient2003
88 #include "inc/Win2003/vss.h"
89 #include "inc/Win2003/vswriter.h"
90 #include "inc/Win2003/vsbackup.h"
94 #define VSSClientGeneric VSSClientVista
95 #include "inc/Win2003/vss.h"
96 #include "inc/Win2003/vswriter.h"
97 #include "inc/Win2003/vsbackup.h"
102 static void JmsgVssApiStatus(JCR *jcr, int msg_status, HRESULT hr, const char *apiName)
105 if (hr == S_OK || hr == VSS_S_ASYNC_FINISHED) {
110 errmsg = "One of the parameter values is not valid.";
113 errmsg = "The caller is out of memory or other system resources.";
116 errmsg = "The caller does not have sufficient backup privileges or is not an administrator.";
118 case VSS_E_INVALID_XML_DOCUMENT:
119 errmsg = "The XML document is not valid.";
121 case VSS_E_OBJECT_NOT_FOUND:
122 errmsg = "The specified file does not exist.";
124 case VSS_E_BAD_STATE:
125 errmsg = "Object is not initialized; called during restore or not called in correct sequence.";
127 case VSS_E_WRITER_INFRASTRUCTURE:
128 errmsg = "The writer infrastructure is not operating properly. Check that the Event Service and VSS have been started, and check for errors associated with those services in the error log.";
130 case VSS_S_ASYNC_CANCELLED:
131 errmsg = "The asynchronous operation was canceled by a previous call to IVssAsync::Cancel.";
133 case VSS_S_ASYNC_PENDING:
134 errmsg = "The asynchronous operation is still running.";
136 case RPC_E_CHANGED_MODE:
137 errmsg = "Previous call to CoInitializeEx specified the multithread apartment (MTA). This call indicates single-threaded apartment has occurred.";
140 errmsg = "No writer found for the current component.";
143 errmsg = "Unexpected error. The error code is logged in the error log file.";
146 Jmsg(jcr, msg_status, 0, "VSS API failure calling \"%s\". ERR=%s\n", apiName, errmsg);
149 #ifndef VSS_WS_FAILED_AT_BACKUPSHUTDOWN
150 #define VSS_WS_FAILED_AT_BACKUPSHUTDOWN (VSS_WRITER_STATE)15
154 static void JmsgVssWriterStatus(JCR *jcr, int msg_status, VSS_WRITER_STATE eWriterStatus, char *writer_name)
158 /* The following are normal states */
159 if (eWriterStatus == VSS_WS_STABLE ||
160 eWriterStatus == VSS_WS_WAITING_FOR_BACKUP_COMPLETE) {
164 /* Potential errors */
165 switch (eWriterStatus) {
168 errmsg = "The writer's state is not known. This is a writer error.";
170 case VSS_WS_WAITING_FOR_FREEZE:
171 errmsg = "The writer is waiting for the freeze state.";
173 case VSS_WS_WAITING_FOR_THAW:
174 errmsg = "The writer is waiting for the thaw state.";
176 case VSS_WS_WAITING_FOR_POST_SNAPSHOT:
177 errmsg = "The writer is waiting for the PostSnapshot state.";
179 case VSS_WS_WAITING_FOR_BACKUP_COMPLETE:
180 errmsg = "The writer is waiting for the requester to finish its backup operation.";
182 case VSS_WS_FAILED_AT_IDENTIFY:
183 errmsg = "The writer vetoed the shadow copy creation process at the writer identification state.";
185 case VSS_WS_FAILED_AT_PREPARE_BACKUP:
186 errmsg = "The writer vetoed the shadow copy creation process during the backup preparation state.";
188 case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
189 errmsg = "The writer vetoed the shadow copy creation process during the PrepareForSnapshot state.";
191 case VSS_WS_FAILED_AT_FREEZE:
192 errmsg = "The writer vetoed the shadow copy creation process during the freeze state.";
194 case VSS_WS_FAILED_AT_THAW:
195 errmsg = "The writer vetoed the shadow copy creation process during the thaw state.";
197 case VSS_WS_FAILED_AT_POST_SNAPSHOT:
198 errmsg = "The writer vetoed the shadow copy creation process during the PostSnapshot state.";
200 case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
201 errmsg = "The shadow copy has been created and the writer failed during the BackupComplete state.";
203 case VSS_WS_FAILED_AT_PRE_RESTORE:
204 errmsg = "The writer failed during the PreRestore state.";
206 case VSS_WS_FAILED_AT_POST_RESTORE:
207 errmsg = "The writer failed during the PostRestore state.";
209 case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
210 errmsg = "The writer failed during the shutdown of the backup application.";
213 Jmsg(jcr, msg_status, 0, "VSS Writer \"%s\" has invalid state. ERR=%s\n", writer_name, errmsg);
218 * some helper functions
224 // Defined in vss.cpp
225 // Append a backslash to the current string
226 wstring AppendBackslash(wstring str);
227 // Get the unique volume name for the given path
228 wstring GetUniqueVolumeNameForPath(wstring path, wstring &rootPath);
230 // Helper macro for quick treatment of case statements for error codes
231 #define GEN_MERGE(A, B) A##B
232 #define GEN_MAKE_W(A) GEN_MERGE(L, A)
234 #define CHECK_CASE_FOR_CONSTANT(value) \
235 case value: return (GEN_MAKE_W(#value));
238 // Convert a writer status into a string
239 inline const wchar_t* GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)
241 switch (eWriterStatus) {
242 CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE);
243 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE);
244 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW);
245 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
246 CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
247 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY);
248 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP);
249 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
250 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE);
251 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW);
252 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT);
253 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
254 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE);
255 CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
257 return L"Error or Undefined";
263 VSSClientGeneric::VSSClientGeneric()
268 VSSClientGeneric::~VSSClientGeneric()
272 // Initialize the COM infrastructure and the internal pointers
273 bool VSSClientGeneric::Initialize(DWORD dwContext, bool bDuringRestore)
275 CComPtr<IVssAsync> pAsync1;
276 VSS_BACKUP_TYPE backup_type;
277 IVssBackupComponents* pVssObj = (IVssBackupComponents*)m_pVssObject;
279 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
280 Dmsg2(0, "VSSClientGeneric::Initialize: p_CreateVssBackupComponents=0x%08X, p_VssFreeSnapshotProperties=0x%08X\n", p_CreateVssBackupComponents, p_VssFreeSnapshotProperties);
281 Jmsg(m_jcr, M_FATAL, 0, "Entry point CreateVssBackupComponents or VssFreeSnapshotProperties missing.\n");
289 m_VolumeList = New(MTab()); // TODO: See if we do this part only in backup
290 if (!m_VolumeList->get()) {
291 Jmsg(m_jcr, M_ERROR, 0, "Unable to list devices and volumes.\n");
297 if (!m_bCoInitializeCalled) {
298 hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
300 Dmsg1(0, "VSSClientGeneric::Initialize: CoInitializeEx returned 0x%08X\n", hr);
301 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "CoInitializeEx");
302 errno = b_errno_win32;
305 m_bCoInitializeCalled = true;
308 // Release the any old IVssBackupComponents interface
314 // Create new internal backup components object
315 hr = p_CreateVssBackupComponents((IVssBackupComponents**)&m_pVssObject);
318 Dmsg2(0, "VSSClientGeneric::Initialize: CreateVssBackupComponents returned 0x%08X. ERR=%s\n",
319 hr, be.bstrerror(b_errno_win32));
320 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "CreateVssBackupComponents");
321 errno = b_errno_win32;
325 /* Define shorthand VssObject with time */
326 pVssObj = (IVssBackupComponents*)m_pVssObject;
329 if (!bDuringRestore) {
330 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
331 if (dwContext != VSS_CTX_BACKUP) {
332 hr = pVssObj->SetContext(dwContext);
334 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetContext returned 0x%08X\n", hr);
335 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "SetContext");
336 errno = b_errno_win32;
342 // 1. InitializeForBackup
343 hr = pVssObj->InitializeForBackup();
345 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->InitializeForBackup returned 0x%08X\n", hr);
346 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "InitializeForBackup");
347 errno = b_errno_win32;
352 switch (m_jcr->getJobLevel()) {
354 backup_type = VSS_BT_FULL;
357 backup_type = VSS_BT_DIFFERENTIAL;
360 backup_type = VSS_BT_INCREMENTAL;
363 Dmsg1(0, "VSSClientGeneric::Initialize: unknown backup level %d\n", m_jcr->getJobLevel());
364 backup_type = VSS_BT_FULL;
367 hr = pVssObj->SetBackupState(true, true, backup_type, false); /* FIXME: need to support partial files - make last parameter true when done */
369 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetBackupState returned 0x%08X\n", hr);
370 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "SetBackupState");
371 errno = b_errno_win32;
375 // 3. GatherWriterMetaData
376 hr = pVssObj->GatherWriterMetadata(&pAsync1.p);
378 Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->GatherWriterMetadata returned 0x%08X\n", hr);
379 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "GatherWriterMetadata");
380 errno = b_errno_win32;
383 // Waits for the async operation to finish and checks the result
384 if (!WaitAndCheckForAsyncOperation(pAsync1.p)) {
385 /* Error message already printed */
386 errno = b_errno_win32;
391 // We are during restore now?
392 m_bDuringRestore = bDuringRestore;
395 m_dwContext = dwContext;
400 bool VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
402 // Wait until the async operation finishes
403 // unfortunately we can't use a timeout here yet.
404 // the interface would allow it on W2k3,
405 // but it is not implemented yet....
409 // Check the result of the asynchronous operation
410 HRESULT hrReturned = S_OK;
412 int timeout = 1800; // 30 minutes ...
416 if (hrReturned != S_OK) {
420 hr = pAsync->QueryStatus(&hrReturned, NULL);
424 } while ((timeout-- > 0) && (hrReturned == VSS_S_ASYNC_PENDING));
426 if (hrReturned == VSS_S_ASYNC_FINISHED) {
430 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "Query Async Status after 30 minute wait");
434 static int volume_cmp(void *e1, void *e2)
436 WCHAR *v1 = (WCHAR *) e1;
437 MTabEntry *v2 = (MTabEntry *) e2;
438 return wcscmp(v1, v2->volumeName);
441 static pthread_mutex_t create_mutex = PTHREAD_MUTEX_INITIALIZER;
443 bool VSSClientGeneric::CreateSnapshots(alist *mount_points)
445 IVssBackupComponents *pVssObj;
449 /* AddToSnapshotSet */
450 CComPtr<IVssAsync> pAsync1;
451 CComPtr<IVssAsync> pAsync2;
454 /* While testing the concurrent snapshot creation, I found out that the entire snapshot
455 * creation process should be protected by a mutex. (InitializeForBackups and CreateSnapshots).
458 /* Create only one snapshot set at a time */
461 /* szDriveLetters contains all drive letters in uppercase */
462 /* if a drive can not being added, it's converted to lowercase in szDriveLetters */
463 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */
464 if (!m_pVssObject || m_bBackupIsInitialized) {
465 Jmsg(m_jcr, M_FATAL, 0, "No pointer to VssObject or Backup is not Initialized\n");
470 m_uidCurrentSnapshotSet = GUID_NULL;
472 pVssObj = (IVssBackupComponents*)m_pVssObject;
474 /* startSnapshotSet */
475 hr = pVssObj->StartSnapshotSet(&m_uidCurrentSnapshotSet);
477 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "StartSnapshotSet");
483 * Now try all paths in case they are mount points
485 for (int i=0; i < mount_points->size(); i++) {
486 wchar_t *p = (wchar_t *)mount_points->get(i);
487 // store uniquevolumname
488 if (SUCCEEDED(pVssObj->AddToSnapshotSet(p, GUID_NULL, &pid))) {
489 MTabEntry *elt = (MTabEntry*)m_VolumeList->entries->search(p, volume_cmp);
490 ASSERT2(elt, "Should find the volume in the list");
491 Jmsg(m_jcr, M_INFO, 0, " Snapshot mount point: %ls\n", elt->first());
492 Dmsg1(50, "AddToSnapshot OK for Vol: %ls\n", p);
494 //Dmsg1(50, "AddToSnapshot() failed for Vol: %ls\n", (LPWSTR)volume.c_str());
495 //Dmsg1(50, "AddToSnapshot() failed for path: %s\n", p);
499 /* PrepareForBackup */
500 hr = pVssObj->PrepareForBackup(&pAsync1.p);
502 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "PrepareForBackup");
503 errno = b_errno_win32;
507 // Waits for the async operation to finish and checks the result
508 if (!WaitAndCheckForAsyncOperation(pAsync1.p)) {
509 /* Error message already printed */
510 errno = b_errno_win32;
514 /* get latest info about writer status */
515 if (!CheckWriterStatus()) {
516 /* Error message already printed */
517 errno = b_errno_win32; /* Error already printed */
522 hr = pVssObj->DoSnapshotSet(&pAsync2.p);
524 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "DoSnapshotSet");
525 errno = b_errno_win32;
529 // Waits for the async operation to finish and checks the result
530 if (!WaitAndCheckForAsyncOperation(pAsync2.p)) {
531 /* Error message already printed */
532 errno = b_errno_win32;
536 /* get latest info about writer status */
537 if (!CheckWriterStatus()) {
538 /* Error message already printed */
539 errno = b_errno_win32; /* Error already printed */
543 /* query snapshot info */
544 QuerySnapshotSet(m_uidCurrentSnapshotSet);
546 m_bBackupIsInitialized = true;
554 bool VSSClientGeneric::CloseBackup()
559 IVssBackupComponents* pVssObj = (IVssBackupComponents*)m_pVssObject;
562 Jmsg(m_jcr, M_FATAL, 0, "VssOject is NULL.\n");
566 /* Create or Delete Snapshot one at a time */
569 CComPtr<IVssAsync> pAsync;
570 m_bBackupIsInitialized = false;
572 hr = pVssObj->BackupComplete(&pAsync.p);
574 // Waits for the async operation to finish and checks the result
575 if (!WaitAndCheckForAsyncOperation(pAsync.p)) {
576 /* Error message already printed */
577 errno = b_errno_win32;
582 JmsgVssApiStatus(m_jcr, M_ERROR, hr, "BackupComplete");
583 errno = b_errno_win32;
584 pVssObj->AbortBackup();
587 /* get latest info about writer status */
590 hr = pVssObj->SaveAsXML(&xml);
597 /* FIXME?: The docs http://msdn.microsoft.com/en-us/library/aa384582%28v=VS.85%29.aspx say this isn't required... */
598 if (m_uidCurrentSnapshotSet != GUID_NULL) {
599 VSS_ID idNonDeletedSnapshotID = GUID_NULL;
602 pVssObj->DeleteSnapshots(
603 m_uidCurrentSnapshotSet,
604 VSS_OBJECT_SNAPSHOT_SET,
607 &idNonDeletedSnapshotID);
609 m_uidCurrentSnapshotSet = GUID_NULL;
612 if (m_bWriterStatusCurrent) {
613 m_bWriterStatusCurrent = false;
614 pVssObj->FreeWriterStatus();
620 // Call CoUninitialize if the CoInitialize was performed sucesfully
621 if (m_bCoInitializeCalled) {
623 m_bCoInitializeCalled = false;
630 WCHAR *VSSClientGeneric::GetMetadata()
635 bool VSSClientGeneric::CloseRestore()
638 IVssBackupComponents* pVssObj = (IVssBackupComponents*)m_pVssObject;
639 CComPtr<IVssAsync> pAsync;
642 Jmsg(m_jcr, M_FATAL, 0, "No pointer to VssObject or Backup is not Initialized\n");
647 /* done by plugin now */
648 if (SUCCEEDED(hr = pVssObj->PostRestore(&pAsync.p))) {
649 // Waits for the async operation to finish and checks the result
650 if (!WaitAndCheckForAsyncOperation(pAsync1.p)) {
651 /* Error message already printed */
652 errno = b_errno_win32;
655 /* get latest info about writer status */
656 if (!CheckWriterStatus()) {
657 /* Error message already printed */
658 errno = b_errno_win32;
662 errno = b_errno_win32;
669 // Query all the shadow copies in the given set
670 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
672 if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
673 Jmsg(m_jcr, M_FATAL, 0, "CreateVssBackupComponents or VssFreeSnapshotProperties API is NULL.\n");
678 if (snapshotSetID == GUID_NULL || m_pVssObject == NULL) {
679 Jmsg(m_jcr, M_FATAL, 0, "snapshotSetID == NULL or VssObject is NULL.\n");
684 IVssBackupComponents* pVssObj = (IVssBackupComponents*) m_pVssObject;
686 // Get list all shadow copies.
687 CComPtr<IVssEnumObject> pIEnumSnapshots;
688 HRESULT hr = pVssObj->Query( GUID_NULL,
691 (IVssEnumObject**)(&pIEnumSnapshots) );
693 // If there are no shadow copies, just return
695 Jmsg(m_jcr, M_FATAL, 0, "No Volume Shadow copies made.\n");
696 errno = b_errno_win32;
700 // Enumerate all shadow copies.
701 VSS_OBJECT_PROP Prop;
702 VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
705 // Get the next element
707 hr = (pIEnumSnapshots.p)->Next(1, &Prop, &ulFetched);
709 // We reached the end of list
710 if (ulFetched == 0) {
714 Dmsg2(DT_VOLUME|50, "Adding %ls => %ls to m_VolumeList\n",
715 Snap.m_pwszOriginalVolumeName, Snap.m_pwszSnapshotDeviceObject);
717 // Print the shadow copy (if not filtered out)
718 if (Snap.m_SnapshotSetId == snapshotSetID) {
719 MTabEntry *elt = (MTabEntry*)m_VolumeList->entries->search(Snap.m_pwszOriginalVolumeName, volume_cmp);
721 Dmsg1(DT_VOLUME|50, "Unable to find [%ls] in the device list\n", Snap.m_pwszOriginalVolumeName);
722 foreach_rblist(elt, m_VolumeList->entries) {
725 Jmsg(m_jcr, M_WARNING, 0, _("Unable to find volume %ls in the device list\n"), Snap.m_pwszOriginalVolumeName);
727 elt->shadowCopyName = bwcsdup(Snap.m_pwszSnapshotDeviceObject);
728 elt->setInSnapshotSet();
731 p_VssFreeSnapshotProperties(&Snap);
736 // Check the status for all selected writers
737 bool VSSClientGeneric::CheckWriterStatus()
740 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp
742 IVssBackupComponents* pVssObj = (IVssBackupComponents*)m_pVssObject;
744 Jmsg(m_jcr, M_FATAL, 0, "Cannot get IVssBackupComponents pointer.\n");
750 if (m_bWriterStatusCurrent) {
751 m_bWriterStatusCurrent = false;
752 pVssObj->FreeWriterStatus();
754 // Gather writer status to detect potential errors
755 CComPtr<IVssAsync> pAsync;
757 HRESULT hr = pVssObj->GatherWriterStatus(&pAsync.p);
759 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "GatherWriterStatus");
760 errno = b_errno_win32;
764 // Waits for the async operation to finish and checks the result
765 if (!WaitAndCheckForAsyncOperation(pAsync.p)) {
766 /* Error message already printed */
767 errno = b_errno_win32;
771 m_bWriterStatusCurrent = true;
773 unsigned cWriters = 0;
775 hr = pVssObj->GetWriterStatusCount(&cWriters);
777 JmsgVssApiStatus(m_jcr, M_FATAL, hr, "GetWriterStatusCount");
778 errno = b_errno_win32;
783 POOLMEM *szBuf = get_pool_memory(PM_FNAME);
784 // Enumerate each writer
785 for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) {
786 VSS_ID idInstance = GUID_NULL;
787 VSS_ID idWriter= GUID_NULL;
788 VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
789 CComBSTR bstrWriterName;
790 HRESULT hrWriterFailure = S_OK;
793 hr = pVssObj->GetWriterStatus(iWriter,
801 JmsgVssApiStatus(m_jcr, M_WARNING, hr, "GetWriterStatus");
802 nState = 0; /* Unknown writer state -- API failed */
804 switch(eWriterStatus) {
805 case VSS_WS_FAILED_AT_IDENTIFY:
806 case VSS_WS_FAILED_AT_PREPARE_BACKUP:
807 case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
808 case VSS_WS_FAILED_AT_FREEZE:
809 case VSS_WS_FAILED_AT_THAW:
810 case VSS_WS_FAILED_AT_POST_SNAPSHOT:
811 case VSS_WS_FAILED_AT_BACKUP_COMPLETE:
812 case VSS_WS_FAILED_AT_PRE_RESTORE:
813 case VSS_WS_FAILED_AT_POST_RESTORE:
814 #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA)
815 case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
817 /* Writer status problem */
818 wchar_2_UTF8(&szBuf, bstrWriterName.p);
819 JmsgVssWriterStatus(m_jcr, M_WARNING, eWriterStatus, szBuf);
820 nState = -1; /* bad writer state */
825 nState = 1; /* Writer state OK */
828 /* store text info */
830 bstrncpy(str, "\"", sizeof(str));
831 wchar_2_UTF8(&szBuf, bstrWriterName.p);
832 bstrncat(str, szBuf, sizeof(str));
833 bstrncat(str, "\", State: 0x", sizeof(str));
834 itoa(eWriterStatus, szBuf, sizeof_pool_memory(szBuf));
835 bstrncat(str, szBuf, sizeof(str));
836 bstrncat(str, " (", sizeof(str));
837 wchar_2_UTF8(&szBuf, GetStringFromWriterStatus(eWriterStatus));
838 bstrncat(str, szBuf, sizeof(str));
839 bstrncat(str, ")", sizeof(str));
840 AppendWriterInfo(nState, (const char *)str);
842 free_pool_memory(szBuf);
847 #endif /* WIN32_VSS */