// Discover excluded components that have file groups outside the shadow set. void GoogleVssClient::DiscoverNonShadowedExcludedComponents( const vector<wstring>& volume_names) { // Discover components that should be excluded from the shadow set having // at least one File Descriptor requiring volumes not in the shadow set. LogDebugMessage( L"Discover components that reside outside the shadow set ..."); for (unsigned idx = 0; idx < writers_.size(); idx++) { VssWriter* writer = &writers_[idx]; if (writer->isExcluded) { continue; } for (unsigned icx = 0; icx < writer->components.size(); icx++) { VssComponent* component = &(writer->components[icx]); if (component->isExcluded) { continue; } for (unsigned vol = 0; vol < component->affected_volumes.size(); vol++) { if (!FindStringInList(component->affected_volumes[vol], volume_names)) { wstring volume_path; GetDisplayNameForVolume(component->affected_volumes[vol], &volume_path); LogDebugMessage( L"- Component '%s' from writer '%s' is excluded from backup " L"(it requires volume %s [%s] in the shadow set)", component->fullPath.c_str(), writer->name.c_str(), component->affected_volumes[vol].c_str(), volume_path.c_str()); component->isExcluded = true; break; } } } } }
// Initialize from a IVssWMComponent void VssComponent::Initialize(wstring writerNameParam, IVssWMComponent * pComponent) { FunctionTracer ft(DBG_INFO); writerName = writerNameParam; // Get the component info PVSSCOMPONENTINFO pInfo = NULL; CHECK_COM(pComponent->GetComponentInfo (&pInfo)); // Initialize local members name = BSTR2WString(pInfo->bstrComponentName); logicalPath = BSTR2WString(pInfo->bstrLogicalPath); caption = BSTR2WString(pInfo->bstrCaption); type = pInfo->type; isSelectable = pInfo->bSelectable; notifyOnBackupComplete = pInfo->bNotifyOnBackupComplete; // Compute the full path fullPath = AppendBackslash(logicalPath) + name; if (fullPath[0] != L'\\') fullPath = wstring(L"\\") + fullPath; // Get file list descriptors for(unsigned i = 0; i < pInfo->cFileCount; i++) { CComPtr<IVssWMFiledesc> pFileDesc; CHECK_COM(pComponent->GetFile (i, &pFileDesc)); VssFileDescriptor desc; desc.Initialize(pFileDesc, VSS_FDT_FILELIST); descriptors.push_back(desc); } // Get database descriptors for(unsigned i = 0; i < pInfo->cDatabases; i++) { CComPtr<IVssWMFiledesc> pFileDesc; CHECK_COM(pComponent->GetDatabaseFile (i, &pFileDesc)); VssFileDescriptor desc; desc.Initialize(pFileDesc, VSS_FDT_DATABASE); descriptors.push_back(desc); } // Get log descriptors for(unsigned i = 0; i < pInfo->cLogFiles; i++) { CComPtr<IVssWMFiledesc> pFileDesc; CHECK_COM(pComponent->GetDatabaseLogFile (i, &pFileDesc)); VssFileDescriptor desc; desc.Initialize(pFileDesc, VSS_FDT_DATABASE_LOG); descriptors.push_back(desc); } #ifdef VSS_SERVER // Get dependencies for(unsigned i = 0; i < pInfo->cDependencies; i++) { CComPtr<IVssWMDependency> pDependency; CHECK_COM(pComponent->GetDependency(i, &pDependency)); VssDependency dependency; dependency.Initialize(pDependency); dependencies.push_back(dependency); } #endif pComponent->FreeComponentInfo (pInfo); // Compute the affected paths and volumes for(unsigned i = 0; i < descriptors.size(); i++) { if (!FindStringInList(descriptors[i].expandedPath, affectedPaths)) affectedPaths.push_back(descriptors[i].expandedPath); if (!FindStringInList(descriptors[i].affectedVolume, affectedVolumes)) affectedVolumes.push_back(descriptors[i].affectedVolume); } sort( affectedPaths.begin( ), affectedPaths.end( ) ); }
// Make the volumes in this list read-write using VDS API void VssClient::MakeVolumesReadWrite(vector<wstring> snapshotVolumes) { FunctionTracer ft(DBG_INFO); ft.Trace(DBG_INFO, L"Clearing read-only on %d volumes ... ", snapshotVolumes.size()); // Get the VDS loader CComPtr<IVdsServiceLoader> pLoader; CHECK_COM(CoCreateInstance(CLSID_VdsLoader, NULL, CLSCTX_LOCAL_SERVER, __uuidof(IVdsServiceLoader), (void **)&pLoader)); // Get the service interface pointer CComPtr<IVdsService> pService; CHECK_COM(pLoader->LoadService(NULL, &pService)); CHECK_COM(pService->WaitForServiceReady()); vector<wstring> clearedVolumes; // Get the unique volume names for the cached snapshot volume names // which might change after the break vector<wstring> snapshotVolumeUniqueNames; for (unsigned i = 0; i < snapshotVolumes.size( ); i++) snapshotVolumeUniqueNames.push_back(GetUniqueVolumeNameForMountPoint(snapshotVolumes[i])); // Enumerate the Software providers HRESULT hr; CComPtr<IEnumVdsObject> pEnumProvider; CHECK_COM(pService->QueryProviders(VDS_QUERY_SOFTWARE_PROVIDERS,&pEnumProvider)); vector< CComPtr<IUnknown> > providers = EnumerateVdsObjects(pEnumProvider); for(unsigned iProvider = 0; iProvider < providers.size(); iProvider++) { // QueryInterface for IVdsSwProvider CComQIPtr<IVdsSwProvider> pSwProvider = providers[iProvider]; ft.Trace(DBG_INFO, L"- Provider %d", iProvider); // Enumerate packs for this provider CComPtr<IEnumVdsObject> pEnumPack; CHECK_COM(pSwProvider->QueryPacks(&pEnumPack)); vector< CComPtr<IUnknown> > packs = EnumerateVdsObjects(pEnumPack); for(unsigned iPack = 0; iPack < packs.size(); iPack++) { // QueryInterface for IVdsPack CComQIPtr<IVdsPack> pPack = packs[iPack]; ft.Trace(DBG_INFO, L"- Pack %d/%d", iPack, iProvider); // Enumerate volumes CComPtr<IEnumVdsObject> pEnumVolumes; hr = pPack->QueryVolumes(&pEnumVolumes); if (FAILED(hr)) { if (hr == VDS_E_INVALID_PACK) { hr = S_OK; } else ft.Trace( DBG_INFO, L"COM Error: GetProperties for VDS pack failed. hr = 0x%08lx", hr); continue; } vector< CComPtr<IUnknown> > volumes = EnumerateVdsObjects(pEnumVolumes); for(unsigned iVol = 0; iVol < volumes.size(); iVol++) { // QueryInterface for IVdsVolumeMF and IVdsVolume CComQIPtr<IVdsVolume> pVolume = volumes[iVol]; // Get volume properties. Ignore deleted volumes VDS_VOLUME_PROP volProp; HRESULT innerHR = pVolume->GetProperties(&volProp); if (innerHR == VDS_E_OBJECT_DELETED ) continue; CHECK_COM_ERROR(innerHR, L"pVolume->GetProperties(&volProp)"); // Skip failed volumes if ( (volProp.status == VDS_VS_FAILED) && (volProp.health == VDS_H_FAILED) || !volProp.pwszName) continue; // Skip hidden volumes (it fails GetVolumeNameForMountPoint) if (volProp.ulFlags & VDS_VF_HIDDEN) continue; // Automatically call CoTaskMemFree on this pointer at the end of scope CAutoComPointer ptrAutoCleanup(volProp.pwszName); // Get the initial device name (normally with the format \\?\GLOBALROOT\Device\HarddiskVolumeXX) wstring name = volProp.pwszName; // Get the unique volume guid name for this device name. wstring uniqueVolumeName = GetUniqueVolumeNameForMountPoint(name); ft.Trace(DBG_INFO, L"- Found volume %s [device = %s] in %d/%d", uniqueVolumeName.c_str(), name.c_str(), iPack, iProvider); // Check to see if this is one of our volumes. If not, continue if (!FindStringInList(uniqueVolumeName, snapshotVolumeUniqueNames)) continue; // Clear the read-only flag ft.WriteLine(L"- Clearing read-only flag for volume %s [%s] ...", uniqueVolumeName.c_str(), name.c_str()); CHECK_COM(pVolume->ClearFlags(VDS_VF_READONLY)); // Force-dismounts the volume // since we want to re-mount the file system as read-write CComQIPtr<IVdsVolumeMF> pVolumeMF = pVolume; ft.WriteLine(L"- Dismounting volume %s ...", name.c_str()); CHECK_COM(pVolumeMF->Dismount(TRUE, FALSE)); clearedVolumes.push_back(uniqueVolumeName); } } } // Check that all volumes have been cleared ... if (clearedVolumes.size() != snapshotVolumeUniqueNames.size()) { ft.WriteLine(L"WARNING: some volumes were not succesfully converted to read-write!"); for (unsigned i = 0; i < snapshotVolumeUniqueNames.size(); i++) if (!FindStringInList(snapshotVolumeUniqueNames[i], clearedVolumes)) ft.WriteLine(L"- Volume %s not found on the system. Clearing the read-only flag failed on it.", snapshotVolumeUniqueNames[i].c_str()); } }