mirror of
https://github.com/uroni/urbackup_frontend_wx.git
synced 2025-10-26 11:19:28 +00:00
1101 lines
28 KiB
C++
1101 lines
28 KiB
C++
#include "SelectWindowsComponents.h"
|
|
#include "Connector.h"
|
|
#include "Settings.h"
|
|
#include <wx/thread.h>
|
|
#include <wx/icon.h>
|
|
#include <fstream>
|
|
#include "stringtools.h"
|
|
#include "checked.xpm"
|
|
#include "unchecked.xpm"
|
|
#ifndef _WIN32
|
|
#include "config.h"
|
|
#endif
|
|
|
|
extern wxString res_path;
|
|
extern wxString ico_ext;
|
|
extern wxBitmapType ico_type;
|
|
extern std::string g_res_path;
|
|
|
|
SelectWindowsComponents::SelectWindowsComponents(wxWindow * parent)
|
|
: GUIWindowsComponents(parent)
|
|
{
|
|
SetIcon(wxIcon(res_path + wxT("backup-ok.") + ico_ext, ico_type));
|
|
|
|
Start(100);
|
|
|
|
wxIcon icons[2];
|
|
icons[0] = wxIcon(unchecked_xpm);
|
|
icons[1] = wxIcon(checked_xpm);
|
|
|
|
icon_width = icons[0].GetWidth();
|
|
icon_height = icons[0].GetHeight();
|
|
|
|
selectList = new wxImageList(icon_width, icon_height, true);
|
|
iconList = new wxImageList(icon_width, icon_height, true);
|
|
|
|
for (size_t i = 0; i < WXSIZEOF(icons); i++)
|
|
selectList->Add(icons[i]);
|
|
|
|
m_treeCtrl1->AssignStateImageList(selectList);
|
|
m_treeCtrl1->AddRoot(_("Loading..."));
|
|
|
|
#ifdef _DEBUG
|
|
settings = new CFileSettingsReader("urbackup/data/settings.cfg");
|
|
#elif _WIN32
|
|
settings = new CFileSettingsReader(g_res_path + "urbackup/data/settings.cfg");
|
|
#else
|
|
settings = new CFileSettingsReader(VARDIR "/urbackup/data/settings.cfg");
|
|
#endif
|
|
|
|
use_orig = 0;
|
|
std::string use_orig_str;
|
|
if (settings->getValue("vss_select_components.use", &use_orig_str))
|
|
use_orig = atoi(use_orig_str.c_str());
|
|
|
|
use_lm_orig = 0;
|
|
std::string use_lm_orig_str;
|
|
if (settings->getValue("vss_select_components.use_lm", &use_lm_orig_str))
|
|
wxString(use_lm_orig_str).ToLongLong(&use_lm_orig);
|
|
|
|
componentReader.Run();
|
|
}
|
|
|
|
SelectWindowsComponents::~SelectWindowsComponents()
|
|
{
|
|
delete settings;
|
|
}
|
|
|
|
void SelectWindowsComponents::Notify(void)
|
|
{
|
|
if (!componentReader.IsAlive())
|
|
{
|
|
Stop();
|
|
componentReader.Wait();
|
|
|
|
m_treeCtrl1->Delete(m_treeCtrl1->GetRootItem());
|
|
wxTreeItemId rootId = m_treeCtrl1->AddRoot(_("Windows components"));
|
|
|
|
m_treeCtrl1->SetItemState(rootId, 0);
|
|
|
|
SComponent* root = componentReader.getRoot();
|
|
|
|
tree_components[rootId] = root;
|
|
tree_items[root] = rootId;
|
|
|
|
addComponents(m_treeCtrl1, iconList, rootId, root, tree_components,
|
|
tree_items, icon_width, icon_height);
|
|
|
|
m_treeCtrl1->Toggle(rootId);
|
|
|
|
m_treeCtrl1->SetImageList(iconList);
|
|
|
|
std::string componentsStr = "default=0";
|
|
settings->getValue("vss_select_components.client", &componentsStr);
|
|
|
|
std::map<std::string, std::string> comps;
|
|
ParseParamStrHttp(componentsStr, &comps);
|
|
|
|
bool has_comps = true;
|
|
if (!comps["all"].empty()
|
|
&& comps["all"] != "0")
|
|
{
|
|
has_comps = false;
|
|
|
|
for (std::map<wxTreeItemId, SComponent*>::iterator it = tree_components.begin();
|
|
it != tree_components.end(); ++it)
|
|
{
|
|
if (m_treeCtrl1->GetItemState(it->first) == 0)
|
|
{
|
|
selectTreeItems(it->second, true);
|
|
}
|
|
}
|
|
}
|
|
else if (!comps["default"].empty()
|
|
&& comps["default"] != "0")
|
|
{
|
|
comps["writer_0"] = "{a65faa63-5ea8-4ebc-9dbd-a0c4db26912a}"; //MS SQL Server 2014
|
|
comps["writer_1"] = "{76fe1ac4-15f7-4bcd-987e-8e1acb462fb7}"; //MS Exchange 2010
|
|
}
|
|
|
|
if(has_comps)
|
|
{
|
|
for (std::map<std::string, std::string>::iterator it = comps.begin();
|
|
it != comps.end(); ++it)
|
|
{
|
|
if (next(it->first, 0, "writer_"))
|
|
{
|
|
std::string idx = getafter("writer_", it->first);
|
|
|
|
std::string componentName = comps["name_" + idx];
|
|
std::string logicalPath = comps["path_" + idx];
|
|
VSS_ID writerId;
|
|
HRESULT hr = IIDFromString(ConvertToUnicode(comps["writer_" + idx]).c_str(), &writerId);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
for (std::map<wxTreeItemId, SComponent*>::iterator it = tree_components.begin();
|
|
it != tree_components.end(); ++it)
|
|
{
|
|
if (!it->second->is_root
|
|
&& it->second->writerId == writerId
|
|
&& (it->second->name == componentName || (componentName.empty() && it->second->writer) )
|
|
&& it->second->logicalPath == logicalPath
|
|
&& m_treeCtrl1->GetItemState(it->first)==0)
|
|
{
|
|
selectTreeItems(it->second, true);
|
|
|
|
if (!it->second->children.empty())
|
|
{
|
|
wxTreeItemId nodeId = tree_items[it->second];
|
|
m_treeCtrl1->ExpandAllChildren(nodeId);
|
|
}
|
|
|
|
SComponent* node = it->second->parent;
|
|
while (node != NULL)
|
|
{
|
|
wxTreeItemId nodeId = tree_items[node];
|
|
m_treeCtrl1->Expand(nodeId);
|
|
node = node->parent;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SelectWindowsComponents::evtOnTreeItemGetTooltip(wxTreeEvent & event)
|
|
{
|
|
SComponent* component = tree_components[event.GetItem()];
|
|
|
|
if (component == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
std::string tooltip =component->name;
|
|
if (!tooltip.empty())
|
|
{
|
|
event.SetToolTip(tooltip);
|
|
}
|
|
}
|
|
|
|
void SelectWindowsComponents::evtOnTreeStateImageClick(wxTreeEvent & event)
|
|
{
|
|
SComponent* component = tree_components[event.GetItem()];
|
|
|
|
if (component == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
bool select = m_treeCtrl1->GetItemState(event.GetItem()) == 0;
|
|
|
|
selectTreeItems(component, select);
|
|
}
|
|
|
|
void SelectWindowsComponents::onOkClick(wxCommandEvent & event)
|
|
{
|
|
std::string res;
|
|
if (m_treeCtrl1->GetItemState(tree_items[componentReader.getRoot()]) == 1)
|
|
{
|
|
res = "all=1";
|
|
}
|
|
else
|
|
{
|
|
size_t idx = 0;
|
|
collectComponents(componentReader.getRoot(), idx, res);
|
|
}
|
|
|
|
int use = use_orig;
|
|
|
|
use |= c_use_value_client;
|
|
|
|
std::string s_data = "vss_select_components=" + res+"\n";
|
|
|
|
if (use != use_orig)
|
|
{
|
|
s_data += "vss_select_components.use=" + nconvert(use) + "\n";
|
|
int64 ctime = wxGetUTCTimeMillis().GetValue() / 1000;
|
|
|
|
if (use_lm_orig > ctime)
|
|
ctime = use_lm_orig + 1;
|
|
|
|
s_data += "default_dirs.use_lm=" + nconvert(ctime) + "\n";
|
|
}
|
|
|
|
Connector::updateSettings(s_data);
|
|
|
|
Close();
|
|
}
|
|
|
|
void SelectWindowsComponents::onCancel(wxCommandEvent & event)
|
|
{
|
|
Close();
|
|
}
|
|
|
|
void SelectWindowsComponents::addComponents(wxTreeCtrl* tree, wxImageList* iconList, wxTreeItemId treeId,
|
|
SComponent * node, std::map<wxTreeItemId, SComponent*>& tree_components,
|
|
std::map<SComponent*, wxTreeItemId>& tree_items, int icon_width, int icon_height)
|
|
{
|
|
for (size_t i = 0; i < node->children.size(); ++i)
|
|
{
|
|
SComponent* child = node->children[i];
|
|
|
|
int image = -1;
|
|
|
|
if (!child->icon.empty())
|
|
{
|
|
wxFileName tempFile;
|
|
tempFile.AssignTempFileName("winCompIco");
|
|
if (tempFile.IsOk())
|
|
{
|
|
std::fstream out;
|
|
out.open(tempFile.GetFullPath().ToStdWstring(), std::ios::out | std::ios::binary);
|
|
|
|
if (out.is_open())
|
|
{
|
|
out.write(child->icon.data(), child->icon.size());
|
|
out.close();
|
|
|
|
wxIcon icon(tempFile.GetFullPath(), wxBITMAP_TYPE_ICO, icon_width, icon_height);
|
|
if (icon.IsOk())
|
|
{
|
|
image = iconList->GetImageCount();
|
|
if (icon.GetWidth() == icon_width
|
|
&& icon.GetHeight() == icon_height)
|
|
{
|
|
iconList->Add(icon);
|
|
}
|
|
else
|
|
{
|
|
iconList->Add(wxBitmap(wxBitmap(icon).ConvertToImage().Rescale(icon_width, icon_height)));
|
|
}
|
|
}
|
|
}
|
|
|
|
DeleteFile(tempFile.GetFullPath().wc_str());
|
|
}
|
|
}
|
|
|
|
int checked = -1;
|
|
|
|
if (child->writer)
|
|
{
|
|
checked = 0;
|
|
}
|
|
else if (child->selectable)
|
|
{
|
|
checked = 0;
|
|
}
|
|
|
|
std::string name = child->displayName;
|
|
if (name.empty())
|
|
{
|
|
name = child->name;
|
|
}
|
|
|
|
wxTreeItemId childId = tree->AppendItem(treeId, name, image);
|
|
|
|
if (checked >= 0)
|
|
{
|
|
tree->SetItemState(childId, checked);
|
|
}
|
|
|
|
tree_components[childId] = child;
|
|
tree_items[child] = childId;
|
|
|
|
addComponents(tree, iconList, childId, child, tree_components, tree_items,
|
|
icon_width, icon_height);
|
|
}
|
|
}
|
|
|
|
void SelectWindowsComponents::selectTreeItems(wxTreeCtrl* tree, std::map<SComponent*, wxTreeItemId>& tree_items,
|
|
SComponent* root, SComponent * node, bool select, bool removeSelect)
|
|
{
|
|
wxTreeItemId nodeId = tree_items[node];
|
|
|
|
int new_itemstate=-5;
|
|
if (tree->GetItemState(nodeId) != wxTREE_ITEMSTATE_NONE)
|
|
{
|
|
if (select && removeSelect)
|
|
{
|
|
tree->SetItemState(nodeId, wxTREE_ITEMSTATE_NONE);
|
|
new_itemstate = wxTREE_ITEMSTATE_NONE;
|
|
}
|
|
else
|
|
{
|
|
new_itemstate = select ? 1 : 0;
|
|
tree->SetItemState(nodeId, new_itemstate);
|
|
}
|
|
}
|
|
else if (!select && !node->writer && node->selectable)
|
|
{
|
|
tree->SetItemState(nodeId, 0);
|
|
new_itemstate = 0;
|
|
}
|
|
|
|
if (!node->writer)
|
|
{
|
|
for (size_t i = 0; i < root->children.size(); ++i)
|
|
{
|
|
if (root->children[i]->writerId == node->writerId)
|
|
{
|
|
bool has_selectable_child = false;
|
|
if (!allChildrenSelected(tree, tree_items, root->children[i], has_selectable_child))
|
|
{
|
|
tree->SetItemState(tree_items[root->children[i]], 0);
|
|
}
|
|
|
|
if (!has_selectable_child)
|
|
{
|
|
tree->SetItemState(tree_items[root->children[i]], select ? 1 : 0);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (node != root)
|
|
{
|
|
bool has_selectable_child = false;
|
|
if (!allChildrenSelected(tree, tree_items, root, has_selectable_child))
|
|
{
|
|
tree->SetItemState(tree_items[root], 0);
|
|
}
|
|
}
|
|
|
|
for(size_t i=0;i<node->dependencies.size();++i)
|
|
{
|
|
selectTreeItems(tree, tree_items, root, node->dependencies[i], select);
|
|
}
|
|
|
|
for (size_t i = 0; i < node->children.size(); ++i)
|
|
{
|
|
bool curr_remove_select = select && !node->writer && node->selectable;
|
|
selectTreeItems(tree, tree_items, root, node->children[i], select, curr_remove_select);
|
|
}
|
|
|
|
if (new_itemstate != -5)
|
|
{
|
|
tree->SetItemState(nodeId, new_itemstate);
|
|
}
|
|
}
|
|
|
|
bool SelectWindowsComponents::hasSelectedChild(wxTreeCtrl* tree, std::map<SComponent*, wxTreeItemId>& tree_items,
|
|
SComponent * node)
|
|
{
|
|
for (size_t i = 0; i < node->children.size(); ++i)
|
|
{
|
|
SComponent* child = node->children[i];
|
|
|
|
wxTreeItemId nodeId = tree_items[child];
|
|
|
|
if (tree->GetItemState(nodeId) == 1)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (hasSelectedChild(tree, tree_items, child))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SelectWindowsComponents::allChildrenSelected(wxTreeCtrl * tree, std::map<SComponent*, wxTreeItemId>& tree_items,
|
|
SComponent * node, bool& has_selectable_child)
|
|
{
|
|
for (size_t i = 0; i < node->children.size(); ++i)
|
|
{
|
|
SComponent* child = node->children[i];
|
|
|
|
wxTreeItemId nodeId = tree_items[child];
|
|
|
|
if (tree->GetItemState(nodeId) != wxTREE_ITEMSTATE_NONE)
|
|
{
|
|
has_selectable_child = true;
|
|
}
|
|
|
|
if (tree->GetItemState(nodeId)!=1
|
|
&& tree->GetItemState(nodeId)!= wxTREE_ITEMSTATE_NONE)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!allChildrenSelected(tree, tree_items, child, has_selectable_child))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void SelectWindowsComponents::selectTreeItems(SComponent * node, bool select, bool removeSelect)
|
|
{
|
|
selectTreeItems(m_treeCtrl1, tree_items, componentReader.getRoot(),
|
|
node, select, removeSelect);
|
|
}
|
|
|
|
void SelectWindowsComponents::collectComponents(SComponent * node, size_t & idx, std::string& res)
|
|
{
|
|
wxTreeItemId nodeId = tree_items[node];
|
|
|
|
int state = m_treeCtrl1->GetItemState(nodeId);
|
|
|
|
if (node != componentReader.getRoot())
|
|
{
|
|
if ( state==1 )
|
|
{
|
|
if (!res.empty())
|
|
{
|
|
res += "&";
|
|
}
|
|
|
|
res += "writer_" + convert(idx) + "=" + convert(node->writerId);
|
|
if (node->writer)
|
|
{
|
|
res += "&name_" + convert(idx) + "=";
|
|
}
|
|
else
|
|
{
|
|
res += "&name_" + convert(idx) + "=" + EscapeParamString(node->name);
|
|
}
|
|
res += "&path_" + convert(idx) + "=" + EscapeParamString(node->logicalPath);
|
|
|
|
++idx;
|
|
}
|
|
}
|
|
|
|
if( state != wxTREE_ITEMSTATE_NONE )
|
|
{
|
|
for (size_t i = 0; i < node->children.size(); ++i)
|
|
{
|
|
collectComponents(node->children[i], idx, res);
|
|
}
|
|
}
|
|
}
|
|
|
|
WindowsComponentReader::WindowsComponentReader()
|
|
: wxThread(wxTHREAD_JOINABLE)
|
|
{
|
|
root.is_root = true;
|
|
}
|
|
|
|
WindowsComponentReader::~WindowsComponentReader()
|
|
{
|
|
for (size_t i = 0; i < components.size(); ++i)
|
|
{
|
|
delete components[i];
|
|
}
|
|
}
|
|
|
|
SComponent * WindowsComponentReader::getRoot()
|
|
{
|
|
return &root;
|
|
}
|
|
|
|
bool WindowsComponentReader::readComponents(const std::string& restoreXml, const std::vector<std::string>& componentXmls,
|
|
const std::vector<SComponent>& filter_except, SComponent & root, std::vector<SComponent*>& components, std::string& errmsg)
|
|
{
|
|
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "CoInitializeEx failed " + GetErrorHResErrStr(hr);
|
|
return false;
|
|
}
|
|
|
|
SCOPED_DECLARE_RELEASE_IUNKNOWN(IVssBackupComponents, backupcom);
|
|
|
|
hr = CreateVssBackupComponents(&backupcom);
|
|
|
|
if (hr != S_OK || backupcom == NULL)
|
|
{
|
|
errmsg = "Error creating backup components " + GetErrorHResErrStr(hr);
|
|
return false;
|
|
}
|
|
|
|
if (!restoreXml.empty())
|
|
{
|
|
hr = backupcom->InitializeForRestore(const_cast<BSTR>(ConvertToUnicode(restoreXml).c_str()));
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "Error initializing components for restore " + GetErrorHResErrStr(hr);
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = backupcom->InitializeForBackup();
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "Error initializing components for backup " + GetErrorHResErrStr(hr);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
UINT nwriters;
|
|
if (restoreXml.empty())
|
|
{
|
|
SCOPED_DECLARE_RELEASE_IUNKNOWN(IVssAsync, pb_result);
|
|
hr = backupcom->GatherWriterMetadata(&pb_result);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "Error gathering writer metadata " + GetErrorHResErrStr(hr);
|
|
return false;
|
|
}
|
|
|
|
if (!wait_for(pb_result, "Gathering writer metadata failed", errmsg))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
hr = backupcom->GetWriterMetadataCount(&nwriters);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "Error getting writer metadata count";
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nwriters = static_cast<UINT>(componentXmls.size());
|
|
}
|
|
|
|
size_t maxDepth = 0;
|
|
|
|
for (UINT i = 0; i < nwriters; ++i)
|
|
{
|
|
VSS_ID writerInstance;
|
|
SCOPED_DECLARE_RELEASE_IUNKNOWN(IVssExamineWriterMetadata, writerMetadata);
|
|
|
|
HRESULT hr;
|
|
if (restoreXml.empty())
|
|
{
|
|
hr = backupcom->GetWriterMetadata(i, &writerInstance, &writerMetadata);
|
|
}
|
|
else
|
|
{
|
|
hr = CreateVssExamineWriterMetadata(const_cast<BSTR>(ConvertToUnicode(componentXmls[i]).c_str()), &writerMetadata);
|
|
}
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "Getting metadata of writer " + convert(i) + " failed. VSS error code " + GetErrorHResErrStr(hr);
|
|
continue;
|
|
}
|
|
|
|
VSS_ID instanceId;
|
|
VSS_ID writerId;
|
|
SCOPED_DECLARE_FREE_BSTR(writerName);
|
|
VSS_USAGE_TYPE usageType;
|
|
VSS_SOURCE_TYPE sourceType;
|
|
hr = writerMetadata->GetIdentity(&instanceId, &writerId, &writerName, &usageType, &sourceType);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "Getting identity of writer " + convert(i) + " failed. VSS error code " + GetErrorHResErrStr(hr);
|
|
continue;
|
|
}
|
|
|
|
//Always skip System writer and ASR writer
|
|
if (convert(writerId) == "{E8132975-6F93-4464-A53E-1050253AE220}"
|
|
|| convert(writerId) == "{BE000CBE-11FE-4426-9C58-531AA6355FC4}")
|
|
{
|
|
continue;
|
|
}
|
|
|
|
std::string writerNameStr = ConvertFromWchar(writerName);
|
|
|
|
UINT nIncludeFiles, nExcludeFiles, nComponents;
|
|
hr = writerMetadata->GetFileCounts(&nIncludeFiles, &nExcludeFiles, &nComponents);
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "GetFileCounts of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr);
|
|
continue;
|
|
}
|
|
|
|
if (nComponents > 0)
|
|
{
|
|
SComponent* component = new SComponent;
|
|
|
|
component->writerId = writerId;
|
|
component->name = writerNameStr;
|
|
component->selectable = true;
|
|
component->writer = true;
|
|
component->parent = &root;
|
|
|
|
components.push_back(component);
|
|
|
|
if (maxDepth == 0) maxDepth = 1;
|
|
}
|
|
|
|
for (UINT j = 0; j < nComponents; ++j)
|
|
{
|
|
SCOPED_DECLARE_RELEASE_IUNKNOWN(IVssWMComponent, wmComponent);
|
|
hr = writerMetadata->GetComponent(j, &wmComponent);
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "Error getting component " + convert(j) + " of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr);
|
|
continue;
|
|
}
|
|
|
|
SCOPED_DECLARE_FREE_COMPONENTINFO(wmComponent, componentInfo);
|
|
hr = wmComponent->GetComponentInfo(&componentInfo);
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "Error getting component info " + convert(j) + " of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr);
|
|
continue;
|
|
}
|
|
|
|
std::string componentNameStr = ConvertFromWchar(componentInfo->bstrComponentName);
|
|
|
|
std::string logicalPathStr;
|
|
if (componentInfo->bstrLogicalPath != NULL)
|
|
{
|
|
logicalPathStr = ConvertFromWchar(componentInfo->bstrLogicalPath);
|
|
}
|
|
|
|
SComponent* component = new SComponent;
|
|
|
|
component->logicalPath = logicalPathStr;
|
|
component->name = componentNameStr;
|
|
component->writerId = writerId;
|
|
component->writer = false;
|
|
if (restoreXml.empty())
|
|
{
|
|
component->selectable = componentInfo->bSelectable == TRUE;
|
|
}
|
|
else
|
|
{
|
|
component->selectable = componentInfo->bSelectableForRestore == TRUE;
|
|
}
|
|
|
|
if (componentInfo->bstrCaption != NULL)
|
|
{
|
|
component->displayName = ConvertFromWchar(componentInfo->bstrCaption);
|
|
}
|
|
|
|
if (componentInfo->cbIcon > 0)
|
|
{
|
|
int abc = 5;
|
|
}
|
|
|
|
bool filtered = true;
|
|
if (filter_except.empty())
|
|
{
|
|
filtered = false;
|
|
}
|
|
else
|
|
{
|
|
for (size_t k = 0; k < filter_except.size(); ++k)
|
|
{
|
|
if (filter_except[k].name == component->name
|
|
&& filter_except[k].writerId == component->writerId
|
|
&& filter_except[k].logicalPath == component->logicalPath)
|
|
{
|
|
filtered = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!filtered)
|
|
{
|
|
component->icon.resize(componentInfo->cbIcon);
|
|
memcpy(component->icon.data(), componentInfo->pbIcon, componentInfo->cbIcon);
|
|
|
|
components.push_back(component);
|
|
|
|
std::vector<std::string> toks;
|
|
TokenizeMail(logicalPathStr, toks, "\\");
|
|
|
|
if (toks.size() + 2 > maxDepth)
|
|
{
|
|
maxDepth = toks.size() + 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
for (size_t depth = 0; depth < maxDepth; ++depth)
|
|
{
|
|
for (size_t i = 0; i < components.size(); ++i)
|
|
{
|
|
std::vector<std::string> toks;
|
|
TokenizeMail(components[i]->logicalPath, toks, "\\");
|
|
|
|
SComponent* parent = NULL;
|
|
if (components[i]->writer
|
|
&& depth == 0)
|
|
{
|
|
parent = &root;
|
|
}
|
|
else if (!components[i]->writer
|
|
&& toks.size() + 1 == depth)
|
|
{
|
|
parent = getComponent(&root, components[i]->writerId, components[i]->logicalPath);
|
|
}
|
|
|
|
if (parent != NULL)
|
|
{
|
|
if (!toks.empty())
|
|
{
|
|
size_t off = 0;
|
|
if (!parent->logicalPath.empty())
|
|
{
|
|
off = parent->logicalPath.size() + 1;
|
|
}
|
|
components[i]->logicalPathComponent = components[i]->logicalPath.substr(off);
|
|
}
|
|
if (components[i]->logicalPathComponent.empty())
|
|
{
|
|
components[i]->logicalPathComponent = components[i]->name;
|
|
}
|
|
else
|
|
{
|
|
components[i]->logicalPathComponent += "\\" + components[i]->name;
|
|
}
|
|
components[i]->parent = parent;
|
|
parent->children.push_back(components[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
for (UINT i = 0; i < nwriters; ++i)
|
|
{
|
|
VSS_ID writerInstance;
|
|
SCOPED_DECLARE_RELEASE_IUNKNOWN(IVssExamineWriterMetadata, writerMetadata);
|
|
HRESULT hr;
|
|
if (restoreXml.empty())
|
|
{
|
|
hr = backupcom->GetWriterMetadata(i, &writerInstance, &writerMetadata);
|
|
}
|
|
else
|
|
{
|
|
hr = CreateVssExamineWriterMetadata(const_cast<BSTR>(ConvertToUnicode(componentXmls[i]).c_str()), &writerMetadata);
|
|
}
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "Getting metadata of writer " + convert(i) + " failed. VSS error code " + GetErrorHResErrStr(hr);
|
|
continue;
|
|
}
|
|
|
|
VSS_ID instanceId;
|
|
VSS_ID writerId;
|
|
SCOPED_DECLARE_FREE_BSTR(writerName);
|
|
VSS_USAGE_TYPE usageType;
|
|
VSS_SOURCE_TYPE sourceType;
|
|
hr = writerMetadata->GetIdentity(&instanceId, &writerId, &writerName, &usageType, &sourceType);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "Getting identity of writer " + convert(i) + " failed. VSS error code " + GetErrorHResErrStr(hr);
|
|
continue;
|
|
}
|
|
|
|
//Always skip System writer and ASR writer
|
|
if (convert(writerId) == "{E8132975-6F93-4464-A53E-1050253AE220}"
|
|
|| convert(writerId) == "{BE000CBE-11FE-4426-9C58-531AA6355FC4}")
|
|
{
|
|
continue;
|
|
}
|
|
|
|
std::string writerNameStr = ConvertFromWchar(writerName);
|
|
|
|
UINT nIncludeFiles, nExcludeFiles, nComponents;
|
|
hr = writerMetadata->GetFileCounts(&nIncludeFiles, &nExcludeFiles, &nComponents);
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "GetFileCounts of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr);
|
|
continue;
|
|
}
|
|
|
|
for (UINT j = 0; j < nComponents; ++j)
|
|
{
|
|
SCOPED_DECLARE_RELEASE_IUNKNOWN(IVssWMComponent, wmComponent);
|
|
hr = writerMetadata->GetComponent(j, &wmComponent);
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "Error getting component " + convert(j) + " of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr);
|
|
continue;
|
|
}
|
|
|
|
SCOPED_DECLARE_FREE_COMPONENTINFO(wmComponent, componentInfo);
|
|
hr = wmComponent->GetComponentInfo(&componentInfo);
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "Error getting component info " + convert(j) + " of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr);
|
|
continue;
|
|
}
|
|
|
|
std::string componentNameStr = ConvertFromWchar(componentInfo->bstrComponentName);
|
|
|
|
std::string logicalPathStr;
|
|
if (componentInfo->bstrLogicalPath != NULL)
|
|
{
|
|
logicalPathStr = ConvertFromWchar(componentInfo->bstrLogicalPath);
|
|
}
|
|
|
|
SComponent* component = getComponent(&root, writerId, logicalPathStr);
|
|
|
|
if (component == NULL)
|
|
{
|
|
errmsg = "Error getting component node of component \"" +
|
|
componentNameStr + "\" of writer \"" + writerNameStr + "\"";
|
|
continue;
|
|
}
|
|
|
|
for (UINT k = 0; k < componentInfo->cDependencies; ++k)
|
|
{
|
|
SCOPED_DECLARE_RELEASE_IUNKNOWN(IVssWMDependency, wmDependency);
|
|
hr = wmComponent->GetDependency(k, &wmDependency);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "Error getting component dependency " + convert(k) + " of component \"" +
|
|
componentNameStr + "\" of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr);
|
|
continue;
|
|
}
|
|
|
|
SCOPED_DECLARE_FREE_BSTR(componentName);
|
|
hr = wmDependency->GetComponentName(&componentName);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "Error getting component name of dependency " + convert(k) + " of component \"" +
|
|
componentNameStr + "\" of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr);
|
|
continue;
|
|
}
|
|
|
|
SCOPED_DECLARE_FREE_BSTR(logicalPath);
|
|
hr = wmDependency->GetLogicalPath(&logicalPath);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "Error getting logical path of dependency " + convert(k) + " of component \"" +
|
|
componentNameStr + "\" of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr);
|
|
continue;
|
|
}
|
|
|
|
std::string dependencylogicalPathStr;
|
|
if (logicalPath != NULL)
|
|
{
|
|
dependencylogicalPathStr = ConvertFromWchar(logicalPath);
|
|
}
|
|
|
|
VSS_ID dependencyWriterId;
|
|
hr = wmDependency->GetWriterId(&dependencyWriterId);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "Error getting writer id of dependency " + convert(k) + " of component \"" +
|
|
componentNameStr + "\" of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr);
|
|
continue;
|
|
}
|
|
|
|
SComponent* dependency = getComponent(&root, dependencyWriterId, dependencylogicalPathStr);
|
|
|
|
if (dependency == NULL)
|
|
{
|
|
errmsg = "Could not find dependency " + convert(k) + " of component \"" +
|
|
componentNameStr + "\" of writer \"" + writerNameStr + "\"";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
wxThread::ExitCode WindowsComponentReader::Entry()
|
|
{
|
|
readComponents(std::string(), std::vector<std::string>(), std::vector<SComponent>(),
|
|
root, components, errmsg);
|
|
|
|
return ExitCode();
|
|
}
|
|
|
|
std::string GetErrorHResErrStr(HRESULT res)
|
|
{
|
|
#define CASE_VSS_ERROR(x) case x: return #x
|
|
switch (res)
|
|
{
|
|
case S_OK:
|
|
return "S_OK";
|
|
case E_INVALIDARG:
|
|
return "E_INVALIDARG";
|
|
case E_OUTOFMEMORY:
|
|
return "E_OUTOFMEMORY";
|
|
case E_UNEXPECTED:
|
|
return "E_UNEXPECTED";
|
|
case E_ACCESSDENIED:
|
|
return "E_ACCESSDENIED";
|
|
case VSS_E_OBJECT_NOT_FOUND:
|
|
return "VSS_E_OBJECT_NOT_FOUND";
|
|
case VSS_E_PROVIDER_VETO:
|
|
return "VSS_E_PROVIDER_VETO";
|
|
case VSS_E_UNEXPECTED_PROVIDER_ERROR:
|
|
return "VSS_E_UNEXPECTED_PROVIDER_ERROR";
|
|
case VSS_E_BAD_STATE:
|
|
return "VSS_E_BAD_STATE";
|
|
case VSS_E_SNAPSHOT_SET_IN_PROGRESS:
|
|
return "VSS_E_SNAPSHOT_SET_IN_PROGRESS";
|
|
case VSS_E_MAXIMUM_NUMBER_OF_VOLUMES_REACHED:
|
|
return "VSS_E_MAXIMUM_NUMBER_OF_VOLUMES_REACHED";
|
|
case VSS_E_MAXIMUM_NUMBER_OF_SNAPSHOTS_REACHED:
|
|
return "VSS_E_MAXIMUM_NUMBER_OF_SNAPSHOTS_REACHED";
|
|
case VSS_E_PROVIDER_NOT_REGISTERED:
|
|
return "VSS_E_PROVIDER_NOT_REGISTERED";
|
|
case VSS_E_VOLUME_NOT_SUPPORTED:
|
|
return "VSS_E_VOLUME_NOT_SUPPORTED";
|
|
case VSS_E_VOLUME_NOT_SUPPORTED_BY_PROVIDER:
|
|
return "VSS_E_VOLUME_NOT_SUPPORTED_BY_PROVIDER";
|
|
CASE_VSS_ERROR(VSS_E_INSUFFICIENT_STORAGE);
|
|
CASE_VSS_ERROR(VSS_E_FLUSH_WRITES_TIMEOUT);
|
|
CASE_VSS_ERROR(VSS_E_HOLD_WRITES_TIMEOUT);
|
|
CASE_VSS_ERROR(VSS_E_NESTED_VOLUME_LIMIT);
|
|
CASE_VSS_ERROR(VSS_E_REBOOT_REQUIRED);
|
|
CASE_VSS_ERROR(VSS_E_TRANSACTION_FREEZE_TIMEOUT);
|
|
CASE_VSS_ERROR(VSS_E_TRANSACTION_THAW_TIMEOUT);
|
|
CASE_VSS_ERROR(S_FALSE);
|
|
CASE_VSS_ERROR(VSS_E_INVALID_XML_DOCUMENT);
|
|
CASE_VSS_ERROR(VSS_E_UNEXPECTED);
|
|
};
|
|
#undef CASE_VSS_ERROR
|
|
return "UNDEF(" + nconvert((long long int)res) + ")";
|
|
}
|
|
|
|
bool WindowsComponentReader::wait_for(IVssAsync * vsasync, const std::string & error_prefix, std::string& errmsg)
|
|
{
|
|
if (vsasync == NULL)
|
|
{
|
|
errmsg = "vsasync is NULL";
|
|
return false;
|
|
}
|
|
|
|
HRESULT hr = vsasync->Wait();
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "Waiting for async result failed " + GetErrorHResErrStr(hr);
|
|
return false;
|
|
}
|
|
|
|
HRESULT res;
|
|
hr = vsasync->QueryStatus(&res, NULL);
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "Querying async result status failed " + GetErrorHResErrStr(hr);
|
|
return false;
|
|
}
|
|
|
|
while (res == VSS_S_ASYNC_PENDING)
|
|
{
|
|
hr = vsasync->Wait();
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "Waiting for async result failed (2) " + GetErrorHResErrStr(hr);
|
|
return false;
|
|
}
|
|
|
|
hr = vsasync->QueryStatus(&res, NULL);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
errmsg = "Querying async result status failed (2) " + GetErrorHResErrStr(hr);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (res != VSS_S_ASYNC_FINISHED)
|
|
{
|
|
errmsg= error_prefix + ". Error code " + GetErrorHResErrStr(res);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
SComponent * WindowsComponentReader::getComponent(SComponent* node, VSS_ID writerId, std::string logical_path)
|
|
{
|
|
if (node->is_root)
|
|
{
|
|
for (size_t i = 0; i < node->children.size(); ++i)
|
|
{
|
|
if (node->children[i]->writerId == writerId)
|
|
{
|
|
if (logical_path.empty())
|
|
{
|
|
return node->children[i];
|
|
}
|
|
|
|
SComponent* ret = getComponent(node->children[i], writerId, logical_path);
|
|
|
|
if (ret == NULL)
|
|
{
|
|
return node->children[i];
|
|
}
|
|
else
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
std::string remainingPath = logical_path;
|
|
std::string nextPath;
|
|
|
|
do
|
|
{
|
|
if (!nextPath.empty())
|
|
{
|
|
nextPath += "\\";
|
|
}
|
|
nextPath += getuntil("\\", remainingPath);
|
|
std::string prevRemainingPath = remainingPath;
|
|
remainingPath = getafter("\\", remainingPath);
|
|
|
|
if (remainingPath.empty())
|
|
{
|
|
nextPath += prevRemainingPath;
|
|
remainingPath.clear();
|
|
}
|
|
|
|
for (size_t i = 0; i < node->children.size(); ++i)
|
|
{
|
|
if (node->children[i]->writerId == writerId
|
|
&& node->children[i]->logicalPathComponent == nextPath)
|
|
{
|
|
if (remainingPath.empty())
|
|
{
|
|
return node->children[i];
|
|
}
|
|
else
|
|
{
|
|
return getComponent(node->children[i], writerId, remainingPath);
|
|
}
|
|
}
|
|
}
|
|
} while (!remainingPath.empty());
|
|
|
|
return NULL;
|
|
}
|