bool VSSClientGeneric::CloseRestore() { //HRESULT hr; IVssBackupComponents* pVssObj = (IVssBackupComponents*)m_pVssObject; CComPtr<IVssAsync> pAsync; if (!pVssObj) { errno = ENOSYS; return false; } #if 0 /* done by plugin now */ if (SUCCEEDED(hr = pVssObj->PostRestore(&pAsync.p))) { // Waits for the async operation to finish and checks the result WaitAndCheckForAsyncOperation(pAsync.p); /* get latest info about writer status */ if (!CheckWriterStatus()) { errno = b_errno_win32; return false; } } else { errno = b_errno_win32; return false; } #endif return true; }
// Query all the shadow copies in the given set void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID) { if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) { Jmsg(m_jcr, M_FATAL, 0, "CreateVssBackupComponents or VssFreeSnapshotProperties API is NULL.\n"); errno = ENOSYS; return; } memset(m_szShadowCopyName,0,sizeof (m_szShadowCopyName)); if (snapshotSetID == GUID_NULL || m_pVssObject == NULL) { Jmsg(m_jcr, M_FATAL, 0, "snapshotSetID == NULL or VssObject is NULL.\n"); errno = ENOSYS; return; } IVssBackupComponents* pVssObj = (IVssBackupComponents*) m_pVssObject; // Get list all shadow copies. CComPtr<IVssEnumObject> pIEnumSnapshots; HRESULT hr = pVssObj->Query( GUID_NULL, VSS_OBJECT_NONE, VSS_OBJECT_SNAPSHOT, (IVssEnumObject**)(&pIEnumSnapshots) ); // If there are no shadow copies, just return if (FAILED(hr)) { Jmsg(m_jcr, M_FATAL, 0, "No Volume Shadow copies made.\n"); errno = b_errno_win32; return; } // Enumerate all shadow copies. VSS_OBJECT_PROP Prop; VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap; while (true) { // Get the next element ULONG ulFetched; hr = (pIEnumSnapshots.p)->Next( 1, &Prop, &ulFetched ); // We reached the end of list if (ulFetched == 0) break; // Print the shadow copy (if not filtered out) if (Snap.m_SnapshotSetId == snapshotSetID) { for (int ch='A'-'A';ch<='Z'-'A';ch++) { if (wcscmp(Snap.m_pwszOriginalVolumeName, m_wszUniqueVolumeName[ch]) == 0) { wcsncpy(m_szShadowCopyName[ch],Snap.m_pwszSnapshotDeviceObject, MAX_PATH-1); break; } } } p_VssFreeSnapshotProperties(&Snap); } errno = 0; }
BOOL VSSClientGeneric::CloseBackup() { BOOL bRet = FALSE; if (!m_pVssObject) errno = ENOSYS; else { IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject; CComPtr<IVssAsync> pAsync; SetVSSPathConvert(NULL, NULL); m_bBackupIsInitialized = false; if (SUCCEEDED(pVss->BackupComplete(&pAsync.p))) { // Waits for the async operation to finish and checks the result WaitAndCheckForAsyncOperation(pAsync.p); bRet = TRUE; } else { errno = b_errno_win32; pVss->AbortBackup(); } /* get latest info about writer status */ CheckWriterStatus(); if (m_uidCurrentSnapshotSet != GUID_NULL) { VSS_ID idNonDeletedSnapshotID = GUID_NULL; LONG lSnapshots; pVss->DeleteSnapshots( m_uidCurrentSnapshotSet, VSS_OBJECT_SNAPSHOT_SET, FALSE, &lSnapshots, &idNonDeletedSnapshotID); m_uidCurrentSnapshotSet = GUID_NULL; } pVss->Release(); m_pVssObject = NULL; } // Call CoUninitialize if the CoInitialize was performed sucesfully if (m_bCoInitializeCalled) { CoUninitialize(); m_bCoInitializeCalled = false; } return bRet; }
// Check the status for all selected writers BOOL VSSClientGeneric::CheckWriterStatus() { /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */ IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject; DestroyWriterInfo(); // Gather writer status to detect potential errors CComPtr<IVssAsync> pAsync; HRESULT hr = pVss->GatherWriterStatus(&pAsync.p); if (FAILED(hr)) { errno = b_errno_win32; return FALSE; } // Waits for the async operation to finish and checks the result WaitAndCheckForAsyncOperation(pAsync.p); unsigned cWriters = 0; hr = pVss->GetWriterStatusCount(&cWriters); if (FAILED(hr)) { errno = b_errno_win32; return FALSE; } int nState; // Enumerate each writer for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) { VSS_ID idInstance = GUID_NULL; VSS_ID idWriter= GUID_NULL; VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN; CComBSTR bstrWriterName; HRESULT hrWriterFailure = S_OK; // Get writer status hr = pVss->GetWriterStatus(iWriter, &idInstance, &idWriter, &bstrWriterName, &eWriterStatus, &hrWriterFailure); if (FAILED(hr)) { /* unknown */ nState = 0; } else { switch(eWriterStatus) { case VSS_WS_FAILED_AT_IDENTIFY: case VSS_WS_FAILED_AT_PREPARE_BACKUP: case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT: case VSS_WS_FAILED_AT_FREEZE: case VSS_WS_FAILED_AT_THAW: case VSS_WS_FAILED_AT_POST_SNAPSHOT: case VSS_WS_FAILED_AT_BACKUP_COMPLETE: case VSS_WS_FAILED_AT_PRE_RESTORE: case VSS_WS_FAILED_AT_POST_RESTORE: #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA) case VSS_WS_FAILED_AT_BACKUPSHUTDOWN: #endif /* failed */ nState = -1; break; default: /* ok */ nState = 1; } } /* store text info */ char str[1000]; char szBuf1[200]; char szBuf2[200]; char szBuf3[200]; wchar_2_UTF8(szBuf1, bstrWriterName.p, sizeof(szBuf1)); itoa(eWriterStatus, szBuf2, sizeof(szBuf2)); wchar_2_UTF8(szBuf3, GetStringFromWriterStatus(eWriterStatus), sizeof(szBuf3)); snprintf(str, sizeof(str), "\"%s\", State: 0x%s (%s)", szBuf1, szBuf2, szBuf3); AppendWriterInfo(nState, (const char *)str); } hr = pVss->FreeWriterStatus(); if (FAILED(hr)) { errno = b_errno_win32; return FALSE; } errno = 0; return TRUE; }
BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters) { /* szDriveLetters contains all drive letters in uppercase */ /* if a drive can not being added, it's converted to lowercase in szDriveLetters */ /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */ if (!m_pVssObject || m_bBackupIsInitialized) { errno = ENOSYS; return FALSE; } m_uidCurrentSnapshotSet = GUID_NULL; IVssBackupComponents *pVss = (IVssBackupComponents*)m_pVssObject; /* startSnapshotSet */ pVss->StartSnapshotSet(&m_uidCurrentSnapshotSet); /* AddToSnapshotSet */ wchar_t szDrive[3]; szDrive[1] = ':'; szDrive[2] = 0; wstring volume; CComPtr<IVssAsync> pAsync1; CComPtr<IVssAsync> pAsync2; VSS_ID pid; for (size_t i=0; i < strlen (szDriveLetters); i++) { szDrive[0] = szDriveLetters[i]; volume = GetUniqueVolumeNameForPath(szDrive); // store uniquevolumname if (SUCCEEDED(pVss->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid))) { wcsncpy (m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR) volume.c_str(), MAX_PATH); } else { szDriveLetters[i] = tolower (szDriveLetters[i]); } } /* PrepareForBackup */ if (FAILED(pVss->PrepareForBackup(&pAsync1.p))) { errno = b_errno_win32; return FALSE; } // Waits for the async operation to finish and checks the result WaitAndCheckForAsyncOperation(pAsync1.p); /* get latest info about writer status */ if (!CheckWriterStatus()) { errno = b_errno_win32; return FALSE; } /* DoSnapShotSet */ if (FAILED(pVss->DoSnapshotSet(&pAsync2.p))) { errno = b_errno_win32; return FALSE; } // Waits for the async operation to finish and checks the result WaitAndCheckForAsyncOperation(pAsync2.p); /* query snapshot info */ QuerySnapshotSet(m_uidCurrentSnapshotSet); SetVSSPathConvert(VSSPathConvert, VSSPathConvertW); m_bBackupIsInitialized = true; return TRUE; }
// Check the status for all selected writers bool VSSClientGeneric::CheckWriterStatus() { /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */ IVssBackupComponents* pVssObj = (IVssBackupComponents*)m_pVssObject; if (!pVssObj) { Jmsg(m_jcr, M_FATAL, 0, "Cannot get IVssBackupComponents pointer.\n"); errno = ENOSYS; return false; } DestroyWriterInfo(); if (m_bWriterStatusCurrent) { m_bWriterStatusCurrent = false; pVssObj->FreeWriterStatus(); } // Gather writer status to detect potential errors CComPtr<IVssAsync> pAsync; HRESULT hr = pVssObj->GatherWriterStatus(&pAsync.p); if (FAILED(hr)) { JmsgVssApiStatus(m_jcr, M_FATAL, hr, "GatherWriterStatus"); errno = b_errno_win32; return false; } // Waits for the async operation to finish and checks the result if (!WaitAndCheckForAsyncOperation(pAsync.p)) { errno = b_errno_win32; return false; } m_bWriterStatusCurrent = true; unsigned cWriters = 0; hr = pVssObj->GetWriterStatusCount(&cWriters); if (FAILED(hr)) { JmsgVssApiStatus(m_jcr, M_FATAL, hr, "GatherWriterStatusCount"); errno = b_errno_win32; return false; } int nState; POOLMEM *szBuf = get_pool_memory(PM_FNAME); // Enumerate each writer for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) { VSS_ID idInstance = GUID_NULL; VSS_ID idWriter= GUID_NULL; VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN; CComBSTR bstrWriterName; HRESULT hrWriterFailure = S_OK; // Get writer status hr = pVssObj->GetWriterStatus(iWriter, &idInstance, &idWriter, &bstrWriterName, &eWriterStatus, &hrWriterFailure); if (FAILED(hr)) { /* Api failed */ JmsgVssApiStatus(m_jcr, M_WARNING, hr, "GetWriterStatus"); nState = 0; /* Unknown writer state -- API failed */ } else { switch(eWriterStatus) { case VSS_WS_FAILED_AT_IDENTIFY: case VSS_WS_FAILED_AT_PREPARE_BACKUP: case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT: case VSS_WS_FAILED_AT_FREEZE: case VSS_WS_FAILED_AT_THAW: case VSS_WS_FAILED_AT_POST_SNAPSHOT: case VSS_WS_FAILED_AT_BACKUP_COMPLETE: case VSS_WS_FAILED_AT_PRE_RESTORE: case VSS_WS_FAILED_AT_POST_RESTORE: #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA) case VSS_WS_FAILED_AT_BACKUPSHUTDOWN: #endif /* Writer status problem */ wchar_2_UTF8(&szBuf, bstrWriterName.p); JmsgVssWriterStatus(m_jcr, M_WARNING, eWriterStatus, szBuf); nState = -1; /* bad writer state */ break; default: /* ok */ nState = 1; /* Writer state OK */ } } /* store text info */ char str[1000]; bstrncpy(str, "\"", sizeof(str)); wchar_2_UTF8(&szBuf, bstrWriterName.p); bstrncat(str, szBuf, sizeof(str)); bstrncat(str, "\", State: 0x", sizeof(str)); itoa(eWriterStatus, szBuf, sizeof_pool_memory(szBuf)); bstrncat(str, szBuf, sizeof(str)); bstrncat(str, " (", sizeof(str)); wchar_2_UTF8(&szBuf, GetStringFromWriterStatus(eWriterStatus)); bstrncat(str, szBuf, sizeof(str)); bstrncat(str, ")", sizeof(str)); AppendWriterInfo(nState, (const char *)str); } free_pool_memory(szBuf); errno = 0; return true; }
bool VSSClientGeneric::CloseBackup() { bool bRet = false; HRESULT hr; BSTR xml; IVssBackupComponents* pVssObj = (IVssBackupComponents*)m_pVssObject; if (!m_pVssObject) { Jmsg(m_jcr, M_FATAL, 0, "VssOject is NULL.\n"); errno = ENOSYS; return bRet; } CComPtr<IVssAsync> pAsync; SetVSSPathConvert(NULL, NULL); m_bBackupIsInitialized = false; hr = pVssObj->BackupComplete(&pAsync.p); if (SUCCEEDED(hr)) { // Waits for the async operation to finish and checks the result WaitAndCheckForAsyncOperation(pAsync.p); bRet = true; } else { JmsgVssApiStatus(m_jcr, M_ERROR, hr, "BackupComplete"); errno = b_errno_win32; pVssObj->AbortBackup(); } /* get latest info about writer status */ CheckWriterStatus(); hr = pVssObj->SaveAsXML(&xml); if (SUCCEEDED(hr)) { m_metadata = xml; } else { m_metadata = NULL; } /* FIXME?: The docs http://msdn.microsoft.com/en-us/library/aa384582%28v=VS.85%29.aspx say this isn't required... */ if (m_uidCurrentSnapshotSet != GUID_NULL) { VSS_ID idNonDeletedSnapshotID = GUID_NULL; LONG lSnapshots; pVssObj->DeleteSnapshots( m_uidCurrentSnapshotSet, VSS_OBJECT_SNAPSHOT_SET, false, &lSnapshots, &idNonDeletedSnapshotID); m_uidCurrentSnapshotSet = GUID_NULL; } if (m_bWriterStatusCurrent) { m_bWriterStatusCurrent = false; pVssObj->FreeWriterStatus(); } pVssObj->Release(); m_pVssObject = NULL; // Call CoUninitialize if the CoInitialize was performed sucesfully if (m_bCoInitializeCalled) { CoUninitialize(); m_bCoInitializeCalled = false; } return bRet; }
// Initialize the COM infrastructure and the internal pointers bool VSSClientGeneric::Initialize(DWORD dwContext, bool bDuringRestore) { CComPtr<IVssAsync> pAsync1; VSS_BACKUP_TYPE backup_type; IVssBackupComponents* pVssObj = (IVssBackupComponents*)m_pVssObject; if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) { Dmsg2(0, "VSSClientGeneric::Initialize: p_CreateVssBackupComponents=0x%08X, p_VssFreeSnapshotProperties=0x%08X\n", p_CreateVssBackupComponents, p_VssFreeSnapshotProperties); Jmsg(m_jcr, M_FATAL, 0, "Entry point CreateVssBackupComponents or VssFreeSnapshotProperties missing.\n"); return false; } HRESULT hr; // Initialize COM if (!m_bCoInitializeCalled) { hr = CoInitialize(NULL); if (FAILED(hr)) { Dmsg1(0, "VSSClientGeneric::Initialize: CoInitialize returned 0x%08X\n", hr); JmsgVssApiStatus(m_jcr, M_FATAL, hr, "CoInitialize"); errno = b_errno_win32; return false; } m_bCoInitializeCalled = true; } // Initialize COM security if (!m_bCoInitializeSecurityCalled) { hr = CoInitializeSecurity( NULL, // Allow *all* VSS writers to communicate back! -1, // Default COM authentication service NULL, // Default COM authorization service NULL, // reserved parameter RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // Strongest COM authentication level RPC_C_IMP_LEVEL_IDENTIFY, // Minimal impersonation abilities NULL, // Default COM authentication settings EOAC_NONE, // No special options NULL // Reserved parameter ); if (FAILED(hr)) { Dmsg1(0, "VSSClientGeneric::Initialize: CoInitializeSecurity returned 0x%08X\n", hr); JmsgVssApiStatus(m_jcr, M_FATAL, hr, "CoInitializeSecurity"); errno = b_errno_win32; return false; } m_bCoInitializeSecurityCalled = true; } // Release the any old IVssBackupComponents interface if (pVssObj) { pVssObj->Release(); m_pVssObject = NULL; } // Create new internal backup components object hr = p_CreateVssBackupComponents((IVssBackupComponents**)&m_pVssObject); if (FAILED(hr)) { berrno be; Dmsg2(0, "VSSClientGeneric::Initialize: CreateVssBackupComponents returned 0x%08X. ERR=%s\n", hr, be.bstrerror(b_errno_win32)); JmsgVssApiStatus(m_jcr, M_FATAL, hr, "CreateVssBackupComponents"); errno = b_errno_win32; return false; } /* Define shorthand VssObject with time */ pVssObj = (IVssBackupComponents*)m_pVssObject; if (!bDuringRestore) { #if defined(B_VSS_W2K3) || defined(B_VSS_VISTA) if (dwContext != VSS_CTX_BACKUP) { hr = pVssObj->SetContext(dwContext); if (FAILED(hr)) { Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetContext returned 0x%08X\n", hr); JmsgVssApiStatus(m_jcr, M_FATAL, hr, "SetContext"); errno = b_errno_win32; return false; } } #endif // 1. InitializeForBackup hr = pVssObj->InitializeForBackup(); if (FAILED(hr)) { Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->InitializeForBackup returned 0x%08X\n", hr); JmsgVssApiStatus(m_jcr, M_FATAL, hr, "InitializeForBackup"); errno = b_errno_win32; return false; } // 2. SetBackupState switch (m_jcr->getJobLevel()) { case L_FULL: backup_type = VSS_BT_FULL; break; case L_DIFFERENTIAL: backup_type = VSS_BT_DIFFERENTIAL; break; case L_INCREMENTAL: backup_type = VSS_BT_INCREMENTAL; break; default: Dmsg1(0, "VSSClientGeneric::Initialize: unknown backup level %d\n", m_jcr->getJobLevel()); backup_type = VSS_BT_FULL; break; } hr = pVssObj->SetBackupState(true, true, backup_type, false); /* FIXME: need to support partial files - make last parameter true when done */ if (FAILED(hr)) { Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->SetBackupState returned 0x%08X\n", hr); JmsgVssApiStatus(m_jcr, M_FATAL, hr, "SetBackupState"); errno = b_errno_win32; return false; } // 3. GatherWriterMetaData hr = pVssObj->GatherWriterMetadata(&pAsync1.p); if (FAILED(hr)) { Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->GatherWriterMetadata returned 0x%08X\n", hr); JmsgVssApiStatus(m_jcr, M_FATAL, hr, "GatherWriterMetadata"); errno = b_errno_win32; return false; } // Waits for the async operation to finish and checks the result if (!WaitAndCheckForAsyncOperation(pAsync1.p)) { /* Error message already printed */ errno = b_errno_win32; return false; } } // We are during restore now? m_bDuringRestore = bDuringRestore; // Keep the context m_dwContext = dwContext; return true; }