urbackup_backend/urbackupclient/client_winvss.cpp
2018-02-22 23:53:44 +01:00

2419 lines
70 KiB
C++

/*************************************************************************
* UrBackup - Client/Server backup system
* Copyright (C) 2011-2016 Martin Raiber
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
#include "client.h"
#include "../Interface/Server.h"
#include "../Interface/File.h"
#include "../Interface/SettingsReader.h"
#include "file_permissions.h"
#include "DirectoryWatcherThread.h"
#include "../urbackupcommon/json.h"
#include <assert.h>
#define CHECK_COM_RESULT_RELEASE(x) { HRESULT r; if( (r=(x))!=S_OK ){ VSSLog(#x+(std::string)" failed. VSS error code "+GetErrorHResErrStr(r), LL_ERROR); printProviderInfo(r); if(backupcom!=NULL){backupcom->AbortBackup();backupcom->Release();} return false; }}
#define CHECK_COM_RESULT_RETURN(x) { HRESULT r; if( (r=(x))!=S_OK ){ VSSLog( #x+(std::string)" failed. VSS error code "+GetErrorHResErrStr(r), LL_ERROR); printProviderInfo(r); return false; }}
#define CHECK_COM_RESULT_RELEASE_S(x) { HRESULT r; if( (r=(x))!=S_OK ){ VSSLog( #x+(std::string)" failed. VSS error code "+GetErrorHResErrStr(r), LL_ERROR); printProviderInfo(r); if(backupcom!=NULL){backupcom->AbortBackup();backupcom->Release();} return ""; }}
#define CHECK_COM_RESULT(x) { HRESULT r; if( (r=(x))!=S_OK ){ VSSLog( #x+(std::string)" failed. VSS error code "+GetErrorHResErrStr(r), LL_ERROR); printProviderInfo(r); }}
#define CHECK_COM_RESULT_OK(x, ok) { HRESULT r; if( (r=(x))!=S_OK ){ ok=false; VSSLog( #x+(std::string)" failed .VSS error code "+GetErrorHResErrStr(r), LL_ERROR); printProviderInfo(r); }}
#define CHECK_COM_RESULT_OK_HR(x, ok, r) { if( (r=(x))!=S_OK ){ ok=false; VSSLog( #x+(std::string)" failed. VSS error code "+GetErrorHResErrStr(r), LL_ERROR); printProviderInfo(r); }}
namespace
{
std::string sortHex(UINT i)
{
UINT bi = big_endian(i);
std::string ret= bytesToHex(reinterpret_cast<unsigned char*>(&bi), sizeof(bi));
strupper(&ret);
return ret;
}
}
namespace
{
template<typename T>
class ReleaseIUnknown
{
public:
ReleaseIUnknown(T*& unknown)
: unknown(unknown) {}
~ReleaseIUnknown() {
if (unknown != NULL) {
unknown->Release();
}
}
private:
T*& unknown;
};
#define TOKENPASTE2(x, y) x ## y
#define TOKENPASTE(x, y) TOKENPASTE2(x, y)
#define SCOPED_DECLARE_RELEASE_IUNKNOWN(t, x) t* x = NULL; ReleaseIUnknown<t> TOKENPASTE(ReleaseIUnknown_,__LINE__) (x)
class FreeBStr
{
public:
FreeBStr(BSTR& bstr)
: bstr(bstr)
{}
~FreeBStr() {
if (bstr != NULL) {
SysFreeString(bstr);
}
}
private:
BSTR& bstr;
};
#define SCOPED_DECLARE_FREE_BSTR(x) BSTR x = NULL; FreeBStr TOKENPASTE(FreeBStr_, __LINE__) (x)
class FreeComponentInfo
{
public:
FreeComponentInfo(IVssWMComponent* wmComponent, PVSSCOMPONENTINFO& componentInfo)
: wmComponent(wmComponent), componentInfo(componentInfo)
{}
~FreeComponentInfo() {
if (wmComponent != NULL && componentInfo != NULL) {
wmComponent->FreeComponentInfo(componentInfo);
}
}
private:
IVssWMComponent* wmComponent;
PVSSCOMPONENTINFO componentInfo;
};
#define SCOPED_DECLARE_FREE_COMPONENTINFO(c, i) PVSSCOMPONENTINFO i = NULL; FreeComponentInfo TOKENPASTE(FreeComponentInfo_,__LINE__) (c, i);
std::string convert(VSS_ID id)
{
WCHAR GuidStr[128] = {};
int rc = StringFromGUID2(id, GuidStr, 128);
if (rc > 0)
{
return Server->ConvertFromWchar(std::wstring(GuidStr, rc - 1));
}
return std::string();
}
class ScopedFreeVssInstance
{
public:
ScopedFreeVssInstance(SVssInstance* instance)
: instance(instance)
{}
~ScopedFreeVssInstance()
{
if (instance->refcount == 0)
{
delete instance;
}
}
private:
SVssInstance* instance;
};
}
void IndexThread::clearContext(SShadowCopyContext& context)
{
if (context.backupcom != NULL)
{
removeBackupcomReferences(context.backupcom);
context.backupcom->Release();
context.backupcom = NULL;
}
}
bool IndexThread::wait_for(IVssAsync *vsasync, const std::string& error_prefix)
{
if (vsasync == NULL)
{
VSSLog("vsasync is NULL", LL_ERROR);
return false;
}
CHECK_COM_RESULT(vsasync->Wait());
HRESULT res;
CHECK_COM_RESULT(vsasync->QueryStatus(&res, NULL));
while (res == VSS_S_ASYNC_PENDING)
{
CHECK_COM_RESULT(vsasync->Wait());
CHECK_COM_RESULT(vsasync->QueryStatus(&res, NULL));
}
if (res != VSS_S_ASYNC_FINISHED)
{
VSSLog(error_prefix+". Error code "+ GetErrorHResErrStr(res), LL_ERROR);
if (res == VSS_E_INSUFFICIENT_STORAGE)
{
VSSLog("Likely cause and solution: The system or snapshot provider does not have enough free storage space on the volumes"
" to be backed up to create snapshots. Please free up some space and then try again.", LL_ERROR);
}
vsasync->Release();
return false;
}
vsasync->Release();
return true;
}
bool IndexThread::checkErrorAndLog(BSTR pbstrWriter, VSS_WRITER_STATE pState, HRESULT pHrResultFailure, std::string& errmsg, int loglevel, bool continue_on_failure, bool* retryable_error)
{
#define FAIL_STATE(x) case x: { state=#x; failure=true; } break
#define OK_STATE(x) case x: { state=#x; ok_state=true; } break
std::string state;
bool failure = false;
bool ok_state = false;
switch (pState)
{
FAIL_STATE(VSS_WS_UNKNOWN);
FAIL_STATE(VSS_WS_FAILED_AT_IDENTIFY);
FAIL_STATE(VSS_WS_FAILED_AT_PREPARE_BACKUP);
FAIL_STATE(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
FAIL_STATE(VSS_WS_FAILED_AT_FREEZE);
FAIL_STATE(VSS_WS_FAILED_AT_THAW);
FAIL_STATE(VSS_WS_FAILED_AT_POST_SNAPSHOT);
FAIL_STATE(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
FAIL_STATE(VSS_WS_FAILED_AT_PRE_RESTORE);
FAIL_STATE(VSS_WS_FAILED_AT_POST_RESTORE);
#ifndef VSS_XP
#ifndef VSS_S03
FAIL_STATE(VSS_WS_FAILED_AT_BACKUPSHUTDOWN);
#endif
#endif
OK_STATE(VSS_WS_STABLE);
OK_STATE(VSS_WS_WAITING_FOR_FREEZE);
OK_STATE(VSS_WS_WAITING_FOR_THAW);
OK_STATE(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
OK_STATE(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
}
#undef FAIL_STATE
#undef OK_STATE
std::string err;
bool has_error = false;
#define HR_ERR(x) case x: { err=#x; has_error=true; } break
switch (pHrResultFailure)
{
case S_OK: { err = "S_OK"; } break;
HR_ERR(VSS_E_WRITERERROR_INCONSISTENTSNAPSHOT);
HR_ERR(VSS_E_WRITERERROR_OUTOFRESOURCES);
HR_ERR(VSS_E_WRITERERROR_TIMEOUT);
HR_ERR(VSS_E_WRITERERROR_RETRYABLE);
HR_ERR(VSS_E_WRITERERROR_NONRETRYABLE);
HR_ERR(VSS_E_WRITER_NOT_RESPONDING);
#ifndef VSS_XP
#ifndef VSS_S03
HR_ERR(VSS_E_WRITER_STATUS_NOT_AVAILABLE);
#endif
#endif
}
#undef HR_ERR
std::string writerName;
if (pbstrWriter)
writerName = Server->ConvertFromWchar(pbstrWriter);
else
writerName = "(NULL)";
if (failure
|| (has_error && (!ok_state || pHrResultFailure!= VSS_E_WRITERERROR_RETRYABLE) ) )
{
const std::string erradd = ". UrBackup will continue with the backup but the associated data may not be consistent.";
std::string nerrmsg = "Writer " + writerName + " has failure state " + state + " with error " + err;
if (retryable_error && pHrResultFailure == VSS_E_WRITERERROR_RETRYABLE)
{
loglevel = LL_INFO;
*retryable_error = true;
}
else if(loglevel<LL_ERROR
&& continue_on_failure)
{
nerrmsg += erradd;
}
VSSLog(nerrmsg, loglevel);
errmsg += nerrmsg;
return false;
}
else
{
VSSLog("Writer " + writerName + " has failure state " + state + " with error " + err + ".", LL_DEBUG);
}
return true;
}
bool IndexThread::check_writer_status(IVssBackupComponents *backupcom, std::string& errmsg, int loglevel, bool continue_on_failure,
const std::vector<VSS_ID>& critical_writers, bool* critical_failure, bool* retryable_error)
{
if (critical_failure != NULL)
*critical_failure = false;
IVssAsync *pb_result;
CHECK_COM_RESULT_RETURN(backupcom->GatherWriterStatus(&pb_result));
if (!wait_for(pb_result, "Gathering writer status failed"))
{
VSSLog("Error while waiting for result from GatherWriterStatus", LL_ERROR);
return false;
}
UINT nWriters;
CHECK_COM_RESULT_RETURN(backupcom->GetWriterStatusCount(&nWriters));
VSSLog("Number of Writers: " + convert(nWriters), LL_DEBUG);
bool has_error = false;
for (UINT i = 0; i<nWriters; ++i)
{
VSS_ID pidInstance;
VSS_ID pidWriter;
BSTR pbstrWriter;
VSS_WRITER_STATE pState;
HRESULT pHrResultFailure;
bool ok = true;
CHECK_COM_RESULT_OK(backupcom->GetWriterStatus(i,
&pidInstance,
&pidWriter,
&pbstrWriter,
&pState,
&pHrResultFailure), ok);
if (ok)
{
bool critical_writer = std::find(critical_writers.begin(), critical_writers.end(), pidWriter)!=critical_writers.end();
if (!checkErrorAndLog(pbstrWriter, pState, pHrResultFailure, errmsg, critical_writer ? LL_ERROR : loglevel, continue_on_failure, retryable_error))
{
if (critical_writer
&& critical_failure!=NULL)
{
*critical_failure = true;
}
has_error = true;
}
SysFreeString(pbstrWriter);
}
}
CHECK_COM_RESULT_RETURN(backupcom->FreeWriterStatus());
return !has_error;
}
std::string IndexThread::GetErrorHResErrStr(HRESULT res)
{
#define CASE_VSS_ERROR(x) case x: return #x
switch (res)
{
case S_OK:
return "S_OK";
case S_FALSE:
return "S_FALSE";
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(VSS_E_UNEXPECTED);
CASE_VSS_ERROR(VSS_E_INVALID_XML_DOCUMENT);
};
#undef CASE_VSS_ERROR
return "UNDEF("+convert((int64)res)+")";
}
void IndexThread::printProviderInfo(HRESULT res)
{
if (res != VSS_E_UNEXPECTED_PROVIDER_ERROR)
{
return;
}
std::string data;
if (os_popen("vssadmin list providers", data) == 0)
{
std::vector<std::string> lines;
Tokenize(data, lines, "\n");
if (lines.size() > 3)
{
VSSLog("VSS provider information:", LL_ERROR);
for (size_t i = 3; i < lines.size(); ++i)
{
std::string cl = trim(lines[i]);
if (!cl.empty())
{
VSSLog(cl, LL_ERROR);
}
}
}
}
}
std::string IndexThread::lookup_shadowcopy(int sid)
{
std::vector<SShadowCopy> scs = cd->getShadowcopies();
for (size_t i = 0; i<scs.size(); ++i)
{
if (scs[i].id == sid)
{
IVssBackupComponents *backupcom = NULL;
CHECK_COM_RESULT_RELEASE_S(CreateVssBackupComponents(&backupcom));
CHECK_COM_RESULT_RELEASE_S(backupcom->InitializeForBackup());
CHECK_COM_RESULT_RELEASE_S(backupcom->SetContext(VSS_CTX_APP_ROLLBACK));
VSS_SNAPSHOT_PROP snap_props = {};
CHECK_COM_RESULT_RELEASE_S(backupcom->GetSnapshotProperties(scs[i].vssid, &snap_props));
std::string ret = Server->ConvertFromWchar(snap_props.m_pwszSnapshotDeviceObject);
VssFreeSnapshotProperties(&snap_props);
backupcom->Release();
return ret;
}
}
return "";
}
bool IndexThread::start_shadowcopy_components(VSS_ID& ssetid, bool* has_active_transaction)
{
std::string wpath;
SCDirs dir;
dir.ref = new SCRef;
dir.ref->starttime = Server->getTimeSeconds();
dir.ref->target = wpath;
dir.ref->clientsubname = index_clientsubname;
dir.ref->for_imagebackup = false;
bool only_ref_val = false;
bool* only_ref=&only_ref_val;
bool ret = start_shadowcopy_win(&dir, wpath, false, true, only_ref, has_active_transaction);
if (ret)
{
ssetid = dir.ref->ssetid;
}
return ret;
}
bool IndexThread::start_shadowcopy_win(SCDirs * dir, std::string &wpath, bool for_imagebackup, bool with_components, bool * &onlyref,
bool* has_active_transaction)
{
const char* crash_consistent_explanation = "This means the files open by this application (e.g. databases) will be backed up in a crash consistent "
"state instead of a properly shutdown state. Properly written applications can recover from system crashes or power failures.";
dir->ref->cbt = false;
std::string wpath_lower = strlower(wpath);
std::vector<SCRef> additional_refs;
std::vector<std::string> selected_vols;
std::vector<VSS_ID> critical_writers;
const int max_tries = 3;
int tries = max_tries;
bool retryable_error = true;
IVssBackupComponents *backupcom = NULL;
while (tries>0 && retryable_error)
{
CHECK_COM_RESULT_RELEASE(CreateVssBackupComponents(&backupcom));
if (!backupcom)
{
VSSLog("backupcom is NULL", LL_ERROR);
return false;
}
CHECK_COM_RESULT_RELEASE(backupcom->InitializeForBackup());
CHECK_COM_RESULT_RELEASE(backupcom->SetBackupState(with_components ? true : false,
with_components ? false : true,
with_components ? VSS_BT_FULL : VSS_BT_COPY, false));
IVssAsync *pb_result;
CHECK_COM_RESULT_RELEASE(backupcom->GatherWriterMetadata(&pb_result));
if (!wait_for(pb_result, "Gathering writer status failed"))
{
backupcom->AbortBackup();
backupcom->Release();
return false;
}
#ifndef VSS_XP
#ifndef VSS_S03
CHECK_COM_RESULT_RELEASE(backupcom->SetContext(VSS_CTX_APP_ROLLBACK));
#endif
#endif
selected_vols.clear();
if (with_components)
{
if (!selectVssComponents(backupcom, selected_vols))
{
VSSLog("Selecting components to backup failed", LL_ERROR);
backupcom->Release();
backupcom = NULL;
return false;
}
if (vss_all_components.empty())
{
VSSLog("Selected no components to backup", LL_INFO);
backupcom->Release();
backupcom = NULL;
return true;
}
critical_writers.clear();
for (size_t i = 0; i < vss_all_components.size(); ++i)
{
if (std::find(critical_writers.begin(),
critical_writers.end(), vss_all_components[i].writerId) != critical_writers.end())
{
critical_writers.push_back(vss_all_components[i].writerId);
}
}
}
if (!wpath.empty()
&& std::find(selected_vols.begin(), selected_vols.end(), wpath_lower)
== selected_vols.end())
{
selected_vols.push_back(wpath_lower);
}
std::vector<std::string> norm_selected_vols = selected_vols;
for (size_t i = 0; i < norm_selected_vols.size(); ++i)
{
normalizeVolume(norm_selected_vols[i]);
}
for (size_t i = 0; i < norm_selected_vols.size(); ++i)
{
std::string& norm_vol = norm_selected_vols[i];
std::vector<std::string> add_vols = getSnapshotGroup(norm_vol, for_imagebackup);
for (size_t j = 0; j < add_vols.size(); ++j)
{
if (std::find(norm_selected_vols.begin(), norm_selected_vols.end(), add_vols[j])
== norm_selected_vols.end())
{
norm_selected_vols.push_back(add_vols[j]);
selected_vols.push_back(add_vols[j]+"\\");
}
}
}
std::string errmsg;
retryable_error = false;
check_writer_status(backupcom, errmsg, LL_WARNING, true, critical_writers, NULL, &retryable_error);
bool b_ok = true;
int tries_snapshot_set = 5;
while (b_ok == true)
{
HRESULT r;
CHECK_COM_RESULT_OK_HR(backupcom->StartSnapshotSet(&dir->ref->ssetid), b_ok, r);
if (b_ok)
{
break;
}
if (b_ok == false && tries_snapshot_set >= 0 && r == VSS_E_SNAPSHOT_SET_IN_PROGRESS)
{
VSSLog("Retrying starting shadow copy in 30s", LL_WARNING);
b_ok = true;
--tries_snapshot_set;
}
Server->wait(30000);
}
if (!b_ok)
{
CHECK_COM_RESULT_RELEASE(backupcom->StartSnapshotSet(&dir->ref->ssetid));
}
additional_refs.clear();
for (size_t i = 0; i < selected_vols.size(); ++i)
{
SCRef nref;
nref.starttime = Server->getTimeSeconds();
nref.target = selected_vols[i];
nref.clientsubname = index_clientsubname;
nref.for_imagebackup = for_imagebackup;
nref.ssetid = dir->ref->ssetid;
nref.backupcom = backupcom;
if (for_imagebackup)
{
nref.starttokens.push_back(starttoken);
}
additional_refs.push_back(nref);
}
for(size_t i=0;i<selected_vols.size();++i)
{
if (tries == max_tries)
{
if (selected_vols[i] == wpath_lower)
{
dir->ref->cbt = prepareCbt(selected_vols[i]);
}
else
{
additional_refs[i].cbt = prepareCbt(selected_vols[i]);
}
}
CHECK_COM_RESULT_RELEASE(backupcom->AddToSnapshotSet(&(Server->ConvertToWchar(selected_vols[i])[0]), GUID_NULL, &additional_refs[i].volid));
if (selected_vols[i] == wpath_lower)
{
dir->ref->volid = additional_refs[i].volid;
}
}
CHECK_COM_RESULT_RELEASE(backupcom->PrepareForBackup(&pb_result));
if (!wait_for(pb_result, "Preparing backup failed"))
{
backupcom->AbortBackup();
backupcom->Release();
return false;
}
retryable_error = false;
check_writer_status(backupcom, errmsg, LL_WARNING, true, critical_writers, NULL, &retryable_error);
CHECK_COM_RESULT_RELEASE(backupcom->DoSnapshotSet(&pb_result));
if (!wait_for(pb_result, "Starting snapshot set failed"))
{
backupcom->AbortBackup();
backupcom->Release();
return false;
}
retryable_error = false;
bool snapshot_ok = false;
bool critical_writer_failure = false;
if (tries>1)
{
snapshot_ok = check_writer_status(backupcom, errmsg, LL_WARNING, true, critical_writers, &critical_writer_failure, &retryable_error);
}
else
{
snapshot_ok = check_writer_status(backupcom, errmsg, LL_WARNING, true, critical_writers, &critical_writer_failure, NULL);
}
--tries;
const char* windows_component_exp = "This client is configured to backup Windows components. "
"When backing up Windows components writer failures are fatal indexing errors. "
"To fix this issue, either configure UrBackup to not backup Windows components or diagnose and repair the "
"failing Windows component. More error details are sometimes in the Windows event log.";
if (!snapshot_ok && !retryable_error)
{
if (!with_components || !critical_writer_failure)
{
VSSLog("Writer is in error state during snapshot creation. Writer data may not be consistent. " + std::string(crash_consistent_explanation), LL_WARNING);
}
else
{
VSSLog(std::string("Writer is in error state during snapshot creation. ")+windows_component_exp, LL_ERROR);
backupcom->AbortBackup();
backupcom->Release();
return false;
}
break;
}
else if (!snapshot_ok)
{
if (tries == 0)
{
if (!with_components || !critical_writer_failure)
{
VSSLog("Creating snapshot failed after three tries. Giving up. Writer data may not be consistent. " + std::string(crash_consistent_explanation), LL_WARNING);
}
else
{
VSSLog(std::string("Creating snapshot failed after three tries. Giving up. ")+windows_component_exp, LL_ERROR);
backupcom->AbortBackup();
backupcom->Release();
return false;
}
break;
}
else
{
VSSLog("Snapshotting failed because of Writer. Retrying in 30s...", LL_WARNING);
}
bool bcom_ok = true;
CHECK_COM_RESULT_OK(backupcom->BackupComplete(&pb_result), bcom_ok);
if (bcom_ok)
{
wait_for(pb_result, "Completing backup with error status failed");
}
#ifndef VSS_XP
#ifndef VSS_S03
if (bcom_ok)
{
LONG dels;
GUID ndels;
CHECK_COM_RESULT_OK(backupcom->DeleteSnapshots(dir->ref->ssetid, VSS_OBJECT_SNAPSHOT_SET, TRUE,
&dels, &ndels), bcom_ok);
if (dels == 0)
{
VSSLog("Deleting shadowcopy failed.", LL_ERROR);
}
}
#endif
#endif
backupcom->Release();
backupcom = NULL;
Server->wait(30000);
}
else
{
break;
}
}
for (size_t i = 0; i < additional_refs.size(); ++i)
{
VSS_SNAPSHOT_PROP snap_props = {};
CHECK_COM_RESULT_RELEASE(backupcom->GetSnapshotProperties(additional_refs[i].volid, &snap_props));
if (snap_props.m_pwszSnapshotDeviceObject == NULL)
{
VSSLog("GetSnapshotProperties did not return a volume path", LL_ERROR);
if (backupcom != NULL) { backupcom->AbortBackup(); backupcom->Release(); }
return false;
}
if (wpath_lower == selected_vols[i])
{
dir->target.erase(0, wpath.size());
dir->ref->volpath = Server->ConvertFromWchar(snap_props.m_pwszSnapshotDeviceObject);
dir->starttime = Server->getTimeSeconds();
dir->target = dir->ref->volpath + os_file_sep() + dir->target;
if (dir->fileserv)
{
shareDir(starttoken, dir->dir, dir->target);
}
}
else
{
additional_refs[i].volpath = Server->ConvertFromWchar(snap_props.m_pwszSnapshotDeviceObject);
}
SShadowCopy tsc;
tsc.vssid = snap_props.m_SnapshotId;
tsc.ssetid = snap_props.m_SnapshotSetId;
if (wpath_lower == selected_vols[i])
{
tsc.target = dir->orig_target;
tsc.orig_target = dir->orig_target;
tsc.filesrv = dir->fileserv;
tsc.tname = dir->dir;
}
else
{
tsc.target = selected_vols[i];
tsc.orig_target = selected_vols[i];
}
tsc.vol = selected_vols[i];
tsc.path = Server->ConvertFromWchar(snap_props.m_pwszSnapshotDeviceObject);
tsc.starttoken = starttoken;
tsc.clientsubname = index_clientsubname;
if (for_imagebackup)
{
tsc.refs = 1;
}
if (wpath_lower == selected_vols[i])
{
dir->ref->save_id = cd->addShadowcopy(tsc);
dir->ref->ok = true;
dir->ref->backupcom = backupcom;
if (with_components)
{
dir->ref->with_writers = true;
}
}
else
{
additional_refs[i].save_id = cd->addShadowcopy(tsc);
additional_refs[i].ok = true;
additional_refs[i].backupcom = backupcom;
if (with_components)
{
additional_refs[i].with_writers = true;
}
}
if (has_active_transaction!=NULL)
{
HANDLE hVolume = CreateFileW((Server->ConvertToWchar(tsc.path)+L"\\").c_str(), GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hVolume != INVALID_HANDLE_VALUE)
{
TXFS_TRANSACTION_ACTIVE_INFO trans_active= {};
DWORD ret_bytes;
BOOL b = DeviceIoControl(hVolume, FSCTL_TXFS_TRANSACTION_ACTIVE, NULL, 0, &trans_active,
sizeof(trans_active), &ret_bytes, NULL);
if (b && trans_active.TransactionsActiveAtSnapshot)
{
Server->Log("Shadow copy has active NTFS transaction", LL_INFO);
*has_active_transaction = true;
}
CloseHandle(hVolume);
}
}
VSSLog("Shadowcopy path: " + tsc.path, LL_DEBUG);
VssFreeSnapshotProperties(&snap_props);
if (onlyref != NULL)
{
*onlyref = false;
}
if (wpath_lower != selected_vols[i])
{
SCRef* nref = new SCRef;
*nref = additional_refs[i];
sc_refs.push_back(nref);
if (for_imagebackup)
{
std::string letter = selected_vols[i];
if (letter.size() == 3
&& letter[1] == ':')
{
letter = letter.substr(0, 2);
strupper(&letter);
}
SCDirs* other_dir = getSCDir(letter, index_clientsubname, for_imagebackup);
if (other_dir != NULL)
{
other_dir->dir = selected_vols[i];
other_dir->fileserv = dir->fileserv;
other_dir->ref = nref;
other_dir->running = dir->running;
other_dir->starttime = dir->starttime;
other_dir->target = selected_vols[i];
}
}
}
}
return true;
}
bool IndexThread::deleteShadowcopyWin(SCDirs *dir)
{
for (size_t i = 0; i < sc_refs.size(); ++i)
{
if (sc_refs[i] != dir->ref
&& sc_refs[i]->ssetid == dir->ref->ssetid)
{
dir->ref->backupcom = NULL;
return true;
}
}
bool ok = true;
IVssBackupComponents *backupcom = dir->ref->backupcom;
for (std::map<std::string, SVssInstance*>::iterator it = vss_name_instances.begin();
it != vss_name_instances.end();)
{
std::map<std::string, SVssInstance*>::iterator it_curr = it;
++it;
if (it_curr->second->backupcom == backupcom)
{
ok = false;
--it_curr->second->refcount;
for (size_t i = 0; i < it_curr->second->parents.size(); ++i)
{
++it_curr->second->parents[i]->issues;
}
if (it_curr->second->refcount == 0)
{
HRESULT hr = it_curr->second->backupcom->SetBackupSucceeded(it_curr->second->instanceId,
it_curr->second->writerId, it_curr->second->componentType,
it_curr->second->logicalPath.empty() ? NULL : Server->ConvertToWchar(it_curr->second->logicalPath).c_str(),
Server->ConvertToWchar(it_curr->second->componentName).c_str(),
false);
if (hr != S_OK)
{
VSSLog("Error setting component \"" + it_curr->second->componentName + "\" with logical path \"" + it_curr->second->logicalPath +
"\" to failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
}
for (size_t i = 0; i < it_curr->second->parents.size(); ++i)
{
SVssInstance* parent = it_curr->second->parents[i];
assert(parent->refcount > 0);
--parent->refcount;
if (parent->refcount == 0)
{
hr = parent->backupcom->SetBackupSucceeded(parent->instanceId,
parent->writerId, parent->componentType,
parent->logicalPath.empty() ? NULL : Server->ConvertToWchar(parent->logicalPath).c_str(),
Server->ConvertToWchar(parent->componentName).c_str(),
false);
if (hr != S_OK)
{
VSSLog("Error setting component \"" + parent->componentName + "\" with logical path \"" + parent->logicalPath +
"\" to failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
}
delete parent;
}
}
delete it_curr->second;
}
vss_name_instances.erase(it_curr);
}
}
IVssAsync *pb_result;
bool bcom_ok = true;
CHECK_COM_RESULT_OK(backupcom->BackupComplete(&pb_result), bcom_ok);
if (bcom_ok)
{
if (!wait_for(pb_result, "Completing backup failed"))
{
ok = false;
}
}
std::vector<VSS_ID> critical_writers;
if (dir->ref->with_writers)
{
for (size_t i = 0; i < vss_all_components.size(); ++i)
{
if (std::find(critical_writers.begin(),
critical_writers.end(), vss_all_components[i].writerId) != critical_writers.end())
{
critical_writers.push_back(vss_all_components[i].writerId);
}
}
}
std::string errmsg;
if (!check_writer_status(backupcom, errmsg, LL_WARNING, !dir->ref->with_writers, critical_writers, NULL, NULL))
{
if (dir->ref->with_writers)
{
ok = false;
}
}
if (dir->ref->with_writers)
{
SCOPED_DECLARE_FREE_BSTR(xml);
HRESULT hr = backupcom->SaveAsXML(&xml);
if (hr == S_OK)
{
std::string component_config_dir = "urbackup\\windows_components_config\\" + conv_filename(starttoken);
writestring(Server->ConvertFromWchar(xml), component_config_dir + "\\backupcom.xml");
}
}
#ifndef VSS_XP
#ifndef VSS_S03
if (bcom_ok)
{
LONG dels;
GUID ndels;
CHECK_COM_RESULT_OK(backupcom->DeleteSnapshots(dir->ref->ssetid, VSS_OBJECT_SNAPSHOT_SET, TRUE,
&dels, &ndels), bcom_ok);
if (dels == 0)
{
VSSLog("Deleting shadowcopy failed.", LL_ERROR);
ok = false;
}
}
#endif
#endif
removeBackupcomReferences(backupcom);
backupcom->Release();
dir->ref->backupcom = NULL;
return ok;
}
void IndexThread::initVss()
{
CHECK_COM_RESULT(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));
CHECK_COM_RESULT(CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL));
}
bool IndexThread::deleteSavedShadowCopyWin(SShadowCopy& scs, SShadowCopyContext& context)
{
IVssBackupComponents *backupcom = NULL;
if (context.backupcom == NULL)
{
CHECK_COM_RESULT_RELEASE(CreateVssBackupComponents(&backupcom));
CHECK_COM_RESULT_RELEASE(backupcom->InitializeForBackup());
CHECK_COM_RESULT_RELEASE(backupcom->SetContext(VSS_CTX_APP_ROLLBACK));
}
else
{
backupcom = context.backupcom;
context.backupcom = NULL;
}
std::vector<SShadowCopy> ascs = cd->getShadowcopies();
bool set_last = true;
for (size_t i = 0; i < ascs.size(); ++i)
{
if (ascs[i].vssid != scs.vssid
&& ascs[i].ssetid == scs.ssetid)
{
VSSLog("Snapshot " + convert(scs.vssid) + " not last snapshot in set " + convert(scs.ssetid) + ". Other snapshot: " + convert(ascs[i].vssid), LL_DEBUG);
set_last = false;
break;
}
}
LONG dels = 0;
GUID ndels;
CHECK_COM_RESULT(backupcom->DeleteSnapshots(set_last ? scs.ssetid : scs.vssid,
set_last ? VSS_OBJECT_SNAPSHOT_SET : VSS_OBJECT_SNAPSHOT, TRUE,
&dels, &ndels));
cd->deleteShadowcopy(scs.id);
if (dels == 0)
{
if (set_last)
{
VSSLog("Error deleting snapshot set " + convert(scs.ssetid), LL_WARNING);
}
else
{
VSSLog("Error deleting snapshot " + convert(scs.vssid), LL_WARNING);
}
}
context.backupcom = backupcom;
if (dels>0)
{
return true;
}
else
{
return false;
}
}
bool IndexThread::getVssSettings()
{
std::string settings_fn = "urbackup/data/settings.cfg";
std::auto_ptr<ISettingsReader> curr_settings(Server->createFileSettingsReader(settings_fn));
vss_select_components.clear();
vss_select_all_components = false;
bool select_default_components = false;
bool ret = false;
if (curr_settings.get() != NULL)
{
std::string val;
if (!curr_settings->getValue("vss_select_components", &val)
&& !curr_settings->getValue("vss_select_components_def", &val))
{
val = "default=1";
}
if (!val.empty())
{
str_map comps;
ParseParamStrHttp(val, &comps, false);
vss_select_components.clear();
for (str_map::iterator it = comps.begin();
it != comps.end(); ++it)
{
if (next(it->first, 0, "writer_"))
{
std::string idx = getafter("writer_", it->first);
SComponent component;
component.componentName = comps["name_" + idx];
component.logicalPath = comps["path_" + idx];
HRESULT hr = IIDFromString(Server->ConvertToWchar(comps["writer_" + idx]).c_str(), &component.writerId);
if (hr==S_OK)
{
vss_select_components.push_back(component);
ret = true;
}
}
}
if (!comps["all"].empty()
&& comps["all"] != "0")
{
vss_select_all_components = true;
}
if (!comps["default"].empty()
&& comps["default"] != "0")
{
select_default_components = true;
}
}
}
if (!vss_select_all_components
&& select_default_components)
{
const char* default_writer_ids[] = {
"{a65faa63-5ea8-4ebc-9dbd-a0c4db26912a}", //MS SQL Server 2014
"{76fe1ac4-15f7-4bcd-987e-8e1acb462fb7}" //MS Exchange 2010
};
for (size_t i = 0; i < sizeof(default_writer_ids) / sizeof(default_writer_ids[0]); ++i)
{
SComponent component;
HRESULT hr = IIDFromString(Server->ConvertToWchar(default_writer_ids[i]).c_str(), &component.writerId);
if (hr == S_OK)
{
vss_select_components.push_back(component);
ret = true;
}
}
}
return ret;
}
bool IndexThread::selectVssComponents(IVssBackupComponents *backupcom
, std::vector<std::string>& selected_vols)
{
UINT nwriters;
CHECK_COM_RESULT_RETURN(backupcom->GetWriterMetadataCount(&nwriters));
std::vector<SComponent> required_dependencies;
vss_all_components.clear();
vss_explicitly_selected_components.clear();
bool added_at_least_one_component;
do
{
added_at_least_one_component = false;
for (UINT i = 0; i < nwriters; ++i)
{
VSS_ID writerInstance;
SCOPED_DECLARE_RELEASE_IUNKNOWN(IVssExamineWriterMetadata, writerMetadata);
HRESULT hr = backupcom->GetWriterMetadata(i, &writerInstance, &writerMetadata);
if (hr != S_OK)
{
VSSLog("Getting metadata of writer " + convert(i) + " failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
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)
{
VSSLog("Getting identity of writer " + convert(i) + " failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
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 = Server->ConvertFromWchar(writerName);
UINT nIncludeFiles, nExcludeFiles, nComponents;
hr = writerMetadata->GetFileCounts(&nIncludeFiles, &nExcludeFiles, &nComponents);
if (hr != S_OK)
{
VSSLog("GetFileCounts of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
continue;
}
for (UINT j = 0; j < nComponents; ++j)
{
SCOPED_DECLARE_RELEASE_IUNKNOWN(IVssWMComponent, wmComponent);
hr = writerMetadata->GetComponent(j, &wmComponent);
if (hr != S_OK)
{
VSSLog("Error getting component " + convert(j) + " of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
continue;
}
SCOPED_DECLARE_FREE_COMPONENTINFO(wmComponent, componentInfo);
hr = wmComponent->GetComponentInfo(&componentInfo);
if (hr != S_OK)
{
VSSLog("Error getting component info " + convert(j) + " of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
continue;
}
std::string componentNameStr = Server->ConvertFromWchar(componentInfo->bstrComponentName);
std::string logicalPathStr;
if (componentInfo->bstrLogicalPath != NULL)
{
logicalPathStr = Server->ConvertFromWchar(componentInfo->bstrLogicalPath);
}
SComponent currComponent;
currComponent.componentName = componentNameStr;
currComponent.logicalPath = logicalPathStr;
currComponent.writerId = writerId;
bool already_selected = std::find(vss_all_components.begin(), vss_all_components.end(),
currComponent)!= vss_all_components.end();
bool already_added = already_selected;
if (!already_selected)
{
for (size_t k = 0; k < vss_explicitly_selected_components.size(); ++k)
{
std::string logicalPathFull = vss_explicitly_selected_components[k].logicalPath;
if (logicalPathFull.empty())
{
logicalPathFull = vss_explicitly_selected_components[k].componentName;
}
else
{
logicalPathFull += "\\" + vss_explicitly_selected_components[k].componentName;
}
if (vss_explicitly_selected_components[k].writerId == writerId
&& next(logicalPathStr, 0, logicalPathFull))
{
already_selected = true;
break;
}
}
}
bool added_curr_component = false;
bool backup_component = vss_select_all_components;
if (!backup_component)
{
for (size_t k = 0; k < vss_select_components.size(); ++k)
{
if (vss_select_components[k].writerId == writerId
&& vss_select_components[k].logicalPath.empty()
&& vss_select_components[k].componentName.empty())
{
backup_component = true;
added_curr_component = true;
}
else if (vss_select_components[k].writerId == writerId)
{
backup_component = true;
}
}
}
if (!already_selected
&& backup_component)
{
if (!componentInfo->bSelectable)
{
hr = backupcom->AddComponent(instanceId, writerId, componentInfo->type, componentInfo->bstrLogicalPath, componentInfo->bstrComponentName);
if (hr != S_OK)
{
VSSLog("Error adding component \"" + componentNameStr + "\" of writer \"" + writerNameStr + "\" to backup (1). VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
}
else
{
added_curr_component = true;
}
}
else
{
if (added_curr_component
|| std::find(vss_select_components.begin(), vss_select_components.end(),
currComponent) != vss_select_components.end())
{
hr = backupcom->AddComponent(instanceId, writerId, componentInfo->type, componentInfo->bstrLogicalPath, componentInfo->bstrComponentName);
if (hr != S_OK)
{
VSSLog("Error adding component \"" + componentNameStr + "\" of writer \"" + writerNameStr + "\" to backup (1). VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
}
else
{
added_curr_component = true;
vss_explicitly_selected_components.push_back(currComponent);
}
}
}
}
if (added_curr_component
|| (!already_added && already_selected) )
{
added_at_least_one_component = true;
std::string captionStr;
if (componentInfo->bstrCaption != NULL)
{
captionStr = Server->ConvertFromWchar(componentInfo->bstrCaption);
}
VSSLog("Component caption=" + captionStr + " name=" + logicalPathStr, LL_INFO);
vss_all_components.push_back(currComponent);
std::vector<SComponent>::iterator
it = std::find(required_dependencies.begin(), required_dependencies.end(),
currComponent);
if (it != required_dependencies.end())
{
required_dependencies.erase(it);
}
for (UINT k = 0; k < componentInfo->cDependencies; ++k)
{
SCOPED_DECLARE_RELEASE_IUNKNOWN(IVssWMDependency, wmDependency);
hr = wmComponent->GetDependency(k, &wmDependency);
if (hr != S_OK)
{
VSSLog("Error getting component dependency " + convert(k) + " of component \"" +
componentNameStr + "\" of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
continue;
}
SCOPED_DECLARE_FREE_BSTR(componentName);
hr = wmDependency->GetComponentName(&componentName);
if (hr != S_OK)
{
VSSLog("Error getting component name of dependency " + convert(k) + " of component \"" +
componentNameStr + "\" of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
continue;
}
SCOPED_DECLARE_FREE_BSTR(logicalPath);
hr = wmDependency->GetLogicalPath(&logicalPath);
if (hr != S_OK)
{
VSSLog("Error getting logical path of dependency " + convert(k) + " of component \"" +
componentNameStr + "\" of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
continue;
}
SComponent newDependency;
newDependency.componentName = Server->ConvertFromWchar(componentName);
if (logicalPath != NULL)
{
newDependency.logicalPath = Server->ConvertFromWchar(logicalPath);
}
hr = wmDependency->GetWriterId(&newDependency.writerId);
if (hr != S_OK)
{
VSSLog("Error getting writer id of dependency " + convert(k) + " of component \"" +
componentNameStr + "\" of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
continue;
}
required_dependencies.push_back(newDependency);
}
for (UINT k = 0; k < componentInfo->cFileCount; ++k)
{
SCOPED_DECLARE_RELEASE_IUNKNOWN(IVssWMFiledesc, wmFile);
hr = wmComponent->GetFile(k, &wmFile);
if (hr != S_OK)
{
VSSLog("Error getting component file desc " + convert(k) + " of component \"" +
componentNameStr + "\" of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
continue;
}
if (!addFilespecVol(wmFile, selected_vols))
{
VSSLog("Error adding file desc " + convert(k) + " of component \"" +
componentNameStr + "\" of writer \"" + writerNameStr + "\" failed.", LL_ERROR);
}
}
for (UINT k = 0; k < componentInfo->cDatabases; ++k)
{
SCOPED_DECLARE_RELEASE_IUNKNOWN(IVssWMFiledesc, wmFile);
hr = wmComponent->GetDatabaseFile(k, &wmFile);
if (hr != S_OK)
{
VSSLog("Error getting database file desc " + convert(k) + " of component \"" +
componentNameStr + "\" of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
continue;
}
if (!addFilespecVol(wmFile, selected_vols))
{
VSSLog("Error adding database file desc " + convert(k) + " of component \"" +
componentNameStr + "\" of writer \"" + writerNameStr + "\" failed.", LL_ERROR);
}
}
for (UINT k = 0; k < componentInfo->cLogFiles; ++k)
{
SCOPED_DECLARE_RELEASE_IUNKNOWN(IVssWMFiledesc, wmFile);
hr = wmComponent->GetDatabaseLogFile(k, &wmFile);
if (hr != S_OK)
{
VSSLog("Error getting database log file desc " + convert(k) + " of component \"" +
componentNameStr + "\" of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
continue;
}
if (!addFilespecVol(wmFile, selected_vols))
{
VSSLog("Error adding database log file desc " + convert(k) + " of component \"" +
componentNameStr + "\" of writer \"" + writerNameStr + "\" failed.", LL_ERROR);
}
}
}
}
}
} while (!required_dependencies.empty() && added_at_least_one_component);
if (!required_dependencies.empty())
{
for (size_t i = 0; i < required_dependencies.size(); ++i)
{
VSSLog("Unresolved VSS component dependency writer id " + convert(required_dependencies[i].writerId) +
" component name \"" + required_dependencies[i].componentName + "\" logical path \"" +
required_dependencies[i].logicalPath + "\"", LL_ERROR);
}
}
return true;
}
bool IndexThread::addFilespecVol(IVssWMFiledesc* wmFile, std::vector<std::string>& selected_vols)
{
SCOPED_DECLARE_FREE_BSTR(bPath);
HRESULT hr = wmFile->GetPath(&bPath);
if (hr != S_OK)
{
VSSLog("Getting path of file spec failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
return false;
}
SCOPED_DECLARE_FREE_BSTR(bAltPath);
wmFile->GetAlternateLocation(&bAltPath);
BSTR tpath = bAltPath != NULL ? bAltPath : bPath;
std::vector<wchar_t> tpathRepl(32768);
DWORD rc = ExpandEnvironmentStringsW(tpath, tpathRepl.data(), static_cast<DWORD>(tpathRepl.size()));
if (rc >= tpathRepl.size() || rc == 0)
{
VSSLog("Replacing environment strings in path \""+ Server->ConvertFromWchar(tpath) + "\" failed", LL_ERROR);
return false;
}
std::string vol = strlower(getVolPath(Server->ConvertFromWchar(tpathRepl.data())));
if (vol.empty())
{
VSSLog("Could not determine volume of path \"" + Server->ConvertFromWchar(tpath) + "\"", LL_ERROR);
return false;
}
if (std::find(selected_vols.begin(), selected_vols.end(), vol) == selected_vols.end())
{
selected_vols.push_back(vol);
}
return true;
}
std::string IndexThread::getVolPath(const std::string& bpath)
{
std::string prefixedbpath = os_file_prefix(bpath);
std::wstring tvolume;
tvolume.resize(prefixedbpath.size() + 100);
DWORD cchBufferLength = static_cast<DWORD>(tvolume.size());
BOOL b = GetVolumePathNameW(Server->ConvertToWchar(prefixedbpath).c_str(), &tvolume[0], cchBufferLength);
if (!b)
{
return std::string();
}
std::string volume = Server->ConvertFromWchar(tvolume.c_str());
std::string volume_lower = strlower(volume);
if (volume.find("\\\\?\\") == 0
&& volume_lower.find("\\\\?\\globalroot") != 0
&& volume_lower.find("\\\\?\\volume") != 0)
{
volume.erase(0, 4);
}
return volume;
}
bool IndexThread::indexVssComponents(VSS_ID ssetid, bool use_db, const std::vector<SCRef*>& past_refs, std::fstream &outfile)
{
IVssBackupComponents* backupcom = NULL;
for (size_t i = 0; i < sc_refs.size(); ++i)
{
if (sc_refs[i]->ssetid == ssetid)
{
backupcom = sc_refs[i]->backupcom;
break;
}
}
if (backupcom == NULL)
{
VSSLog("Could not find backupcom for snapshot set " + convert(ssetid), LL_ERROR);
return false;
}
for (std::map<std::string, SVssInstance*>::iterator it = vss_name_instances.begin();
it != vss_name_instances.end();)
{
if (!next(it->first, 0, starttoken + "|"))
{
++it;
continue;
}
--it->second->refcount;
if (it->second->refcount == 0)
{
for (size_t i = 0; i < it->second->parents.size(); ++i)
{
--it->second->parents[i]->refcount;
if (it->second->parents[i]->refcount == 0)
{
delete it->second->parents[i];
}
}
delete it->second;
}
std::map<std::string, SVssInstance*>::iterator delit = it++;
vss_name_instances.erase(delit);
}
std::string component_config_dir = Server->getServerWorkingDir() + "\\urbackup\\windows_components_config\\" + conv_filename(starttoken);
std::string components_dir = Server->getServerWorkingDir()+"\\urbackup\\windows_components";
if (os_directory_exists(component_config_dir))
{
if (!os_remove_nonempty_dir(component_config_dir))
{
VSSLog("Error removing directory \""+ component_config_dir+"\". " + os_last_error_str(), LL_ERROR);
return false;
}
}
if (!os_create_dir_recursive(component_config_dir))
{
VSSLog("Error creating directory \""+ component_config_dir+"\". " + os_last_error_str(), LL_ERROR);
return false;
}
writestring("", component_config_dir + "\\backupcom.xml");
if (!change_file_permissions_admin_only(component_config_dir))
{
VSSLog("Error setting permissions of directory \""+ component_config_dir+"\" to admin only. " + os_last_error_str(), LL_ERROR);
return false;
}
if (!os_directory_exists(components_dir))
{
if (!os_create_dir_recursive(components_dir))
{
VSSLog("Error creating directory \"" + components_dir + "\". " + os_last_error_str(), LL_ERROR);
return false;
}
}
if (!os_directory_exists(components_dir + os_file_sep() + "dummy"))
{
if (!os_create_dir(components_dir + os_file_sep() + "dummy"))
{
VSSLog("Error creating directory \"" + components_dir + os_file_sep() + "dummy" + "\". " + os_last_error_str(), LL_ERROR);
return false;
}
}
shareDir(starttoken, "windows_components_config", component_config_dir);
shareDir(starttoken, "windows_components", components_dir);
UINT nwriters;
CHECK_COM_RESULT_RETURN(backupcom->GetWriterMetadataCount(&nwriters));
std::vector<std::string> component_config_files;
std::vector<int64> component_config_file_size;
JSON::Object info_json;
JSON::Array selected_components_json;
std::string pretty_symlink_struct = "d\"windows_components\" 0 "+convert(getChangeIndicator(components_dir))+"\n";
int64 pretty_print_id_add = 1;
for (UINT i = 0; i < nwriters; ++i)
{
VSS_ID writerInstance;
SCOPED_DECLARE_RELEASE_IUNKNOWN(IVssExamineWriterMetadata, writerMetadata);
HRESULT hr = backupcom->GetWriterMetadata(i, &writerInstance, &writerMetadata);
if (hr != S_OK)
{
VSSLog("Getting metadata of writer " + convert(i) + " failed while indexing. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
return false;
}
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)
{
VSSLog("Getting identity of writer " + convert(i) + " failed while indexing. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
return false;
}
std::string writerNameStr = Server->ConvertFromWchar(writerName);
UINT nIncludeFiles, nExcludeFiles, nComponents;
hr = writerMetadata->GetFileCounts(&nIncludeFiles, &nExcludeFiles, &nComponents);
if (hr != S_OK)
{
VSSLog("GetFileCounts of writer \"" + writerNameStr + "\" failed while indexing. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
return false;
}
bool has_component = false;
std::string writerNameStrShort = writerNameStr;
if (writerNameStrShort.size() > 100)
{
writerNameStrShort = writerNameStr.substr(0, 100);
}
std::string curr_dir = conv_filename(writerNameStrShort) + "_" + convert(writerId);
std::string named_path_base = ".symlink_"+ curr_dir;
std::string pretty_symlink_struct_writer = "d\"" + sortHex(i) + "_" + conv_filename(writerNameStrShort) + "\" 0 ";
++pretty_print_id_add;
std::string pretty_struct_base = components_dir + os_file_sep() + sortHex(i) + "_" + conv_filename(writerNameStrShort);
if (!os_directory_exists(pretty_struct_base))
{
os_create_dir(pretty_struct_base);
}
pretty_symlink_struct_writer += convert(getChangeIndicator(pretty_struct_base)) + "\n";
std::vector<std::string> exclude_files;
std::vector<SVssInstance*> component_vss_instances;
for (UINT j = 0; j < nComponents; ++j)
{
SCOPED_DECLARE_RELEASE_IUNKNOWN(IVssWMComponent, wmComponent);
hr = writerMetadata->GetComponent(j, &wmComponent);
if (hr != S_OK)
{
VSSLog("Error getting component " + convert(j) + " of writer \"" + writerNameStr + "\" failed while indexing. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
return false;
}
SCOPED_DECLARE_FREE_COMPONENTINFO(wmComponent, componentInfo);
hr = wmComponent->GetComponentInfo(&componentInfo);
if (hr != S_OK)
{
VSSLog("Error getting component info " + convert(j) + " of writer \"" + writerNameStr + "\" failed while indexing. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
return false;
}
std::string componentNameStr = Server->ConvertFromWchar(componentInfo->bstrComponentName);
std::string logicalPathStr;
if (componentInfo->bstrLogicalPath != NULL)
{
logicalPathStr = Server->ConvertFromWchar(componentInfo->bstrLogicalPath);
}
std::string componentNameStrShort = componentNameStr;
if (componentNameStrShort.size() > 100)
{
componentNameStrShort = componentNameStr.substr(0, 100);
}
std::string logicalPathHash;
if (!logicalPathStr.empty())
{
logicalPathHash = "_" + Server->GenerateHexMD5(logicalPathStr);
}
curr_dir = sortHex(j) + "_" + conv_filename(componentNameStrShort);
std::string named_path = named_path_base + logicalPathHash + "_" + conv_filename(componentNameStrShort);
SComponent currComponent;
currComponent.componentName = componentNameStr;
currComponent.logicalPath = logicalPathStr;
currComponent.writerId = writerId;
if (std::find(vss_all_components.begin(),
vss_all_components.end(), currComponent)!=vss_all_components.end())
{
if (!has_component)
{
if (!getExcludedFiles(writerMetadata, nExcludeFiles, exclude_files))
{
VSSLog("Error getting excluded files of writer \"" + writerNameStr + "\" failed while indexing.", LL_ERROR);
return false;
}
}
JSON::Object currComponentJson;
currComponentJson.set("writerId", convert(writerId));
currComponentJson.set("logicalPath", logicalPathStr);
currComponentJson.set("componentName", componentNameStr);
selected_components_json.add(currComponentJson);
SVssInstance* vssInstance = new SVssInstance;
ScopedFreeVssInstance freeVssInstance(vssInstance);
vssInstance->refcount = 0;
vssInstance->issues = 0;
vssInstance->componentName = componentNameStr;
vssInstance->logicalPath = logicalPathStr;
vssInstance->writerId = writerId;
vssInstance->instanceId = instanceId;
vssInstance->backupcom = backupcom;
vssInstance->componentType = componentInfo->type;
vssInstance->set_succeeded = std::find(vss_explicitly_selected_components.begin(),
vss_explicitly_selected_components.end(), currComponent) != vss_explicitly_selected_components.end();
std::string pretty_struct_component_path = pretty_struct_base + os_file_sep() + curr_dir;
if (!os_directory_exists(os_file_prefix(pretty_struct_component_path)))
{
os_create_dir(os_file_prefix(pretty_struct_component_path));
}
pretty_symlink_struct_writer += "d\"" + curr_dir + "\" 0 "+convert(getChangeIndicator(pretty_struct_component_path))+"\n";
++pretty_print_id_add;
has_component = true;
for (UINT k = 0; k < componentInfo->cFileCount; ++k)
{
SCOPED_DECLARE_RELEASE_IUNKNOWN(IVssWMFiledesc, wmFile);
hr = wmComponent->GetFile(k, &wmFile);
if (hr != S_OK)
{
VSSLog("Error getting component file desc " + convert(k) + " of component \"" +
componentNameStr + "\" of writer \"" + writerNameStr + "\" failed while indexing. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
return false;
}
std::string symlink_fn = pretty_struct_component_path + os_file_sep() + "files" + sortHex(k);
if ((os_get_file_type(os_file_prefix(symlink_fn)) & EFileType_Symlink) == 0)
{
bool is_dir = true;
os_link_symbolic(os_file_prefix(components_dir + os_file_sep() + "dummy"),
os_file_prefix(symlink_fn), NULL, &is_dir);
}
pretty_symlink_struct_writer += "d\"files" + sortHex(k) + "\" 0 "+ convert(getChangeIndicator(symlink_fn))+"#special=1&sym_target="+ EscapeParamString(named_path + "_files" + sortHex(k))+"\nu\n";
++pretty_print_id_add;
if (!addFiles(wmFile, ssetid, past_refs, named_path+"_files"+ sortHex(k), use_db, exclude_files, outfile))
{
VSSLog("Error indexing files " + convert(k) + " of component \"" +
componentNameStr + "\" of writer \"" + writerNameStr + "\".", LL_ERROR);
return false;
}
vss_name_instances[starttoken + "|" + named_path + "_files" + sortHex(k)] = vssInstance;
++vssInstance->refcount;
}
for (UINT k = 0; k < componentInfo->cDatabases; ++k)
{
SCOPED_DECLARE_RELEASE_IUNKNOWN(IVssWMFiledesc, wmFile);
hr = wmComponent->GetDatabaseFile(k, &wmFile);
if (hr != S_OK)
{
VSSLog("Error getting database file desc " + convert(k) + " of component \"" +
componentNameStr + "\" of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
return false;
}
std::string symlink_fn = pretty_struct_component_path + os_file_sep() + "database" + sortHex(k);
if ((os_get_file_type(os_file_prefix(symlink_fn)) & EFileType_Symlink) == 0)
{
bool is_dir = true;
os_link_symbolic(os_file_prefix( components_dir + os_file_sep() + "dummy"),
os_file_prefix(symlink_fn), NULL, &is_dir);
}
pretty_symlink_struct_writer += "d\"database" + sortHex(k) + "\" 0 " + convert(getChangeIndicator(symlink_fn)) + "#special=1&sym_target=" + EscapeParamString(named_path + "_database" + sortHex(k)) + "\nu\n";
++pretty_print_id_add;
if (!addFiles(wmFile, ssetid, past_refs, named_path+"_database"+ sortHex(k), use_db, exclude_files, outfile))
{
VSSLog("Error indexing database file " + sortHex(k) + " of component \"" +
componentNameStr + "\" of writer \"" + writerNameStr + "\".", LL_ERROR);
return false;
}
vss_name_instances[starttoken + "|" + named_path + "_database" + sortHex(k)] = vssInstance;
++vssInstance->refcount;
}
for (UINT k = 0; k < componentInfo->cLogFiles; ++k)
{
SCOPED_DECLARE_RELEASE_IUNKNOWN(IVssWMFiledesc, wmFile);
hr = wmComponent->GetDatabaseLogFile(k, &wmFile);
if (hr != S_OK)
{
VSSLog("Error getting database log file desc " + convert(k) + " of component \"" +
componentNameStr + "\" of writer \"" + writerNameStr + "\" failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
return false;
}
std::string symlink_fn = pretty_struct_component_path + os_file_sep() + "database_log" + sortHex(k);
if ((os_get_file_type(os_file_prefix(symlink_fn)) & EFileType_Symlink) == 0)
{
bool is_dir = true;
os_link_symbolic(os_file_prefix( components_dir + os_file_sep() + "dummy"),
os_file_prefix(symlink_fn), NULL, &is_dir);
}
pretty_symlink_struct_writer += "d\"database_log" + sortHex(k) + "\" 0 " + convert(getChangeIndicator(symlink_fn))+ "#special=1&sym_target=" + EscapeParamString(named_path + "_database_log" + sortHex(k)) + "\nu\n";
++pretty_print_id_add;
if (!addFiles(wmFile, ssetid, past_refs, named_path+"_database_log"+ sortHex(k), use_db, exclude_files, outfile))
{
VSSLog("Error indexing database log file " + sortHex(k) + " of component \"" +
componentNameStr + "\" of writer \"" + writerNameStr + "\".", LL_ERROR);
return false;
}
vss_name_instances[starttoken + "|" + named_path + "_database_log" + sortHex(k)] = vssInstance;
++vssInstance->refcount;
}
std::string completeLogicalPathStr = logicalPathStr;
if (completeLogicalPathStr.empty())
{
completeLogicalPathStr = componentNameStr;
}
else
{
completeLogicalPathStr += "\\" + componentNameStr;
}
for (std::vector<SVssInstance*>::iterator it = component_vss_instances.begin();
it != component_vss_instances.end(); ++it)
{
std::string logicalPath = (*it)->logicalPath;
if (logicalPath.empty())
{
logicalPath = (*it)->componentName;
}
else
{
logicalPath += "\\" + (*it)->componentName;
}
if (*it != vssInstance
&& completeLogicalPathStr != logicalPath )
{
if (next(completeLogicalPathStr, 0, logicalPath))
{
bool already_present = false;
for (size_t k = 0; k < vssInstance->parents.size(); ++k)
{
if (*vssInstance->parents[k] == *(*it))
{
already_present = true;
}
}
if (!already_present)
{
vssInstance->parents.push_back(*it);
++(*it)->refcount;
}
}
else if(next(logicalPath, 0, completeLogicalPathStr))
{
bool already_present = false;
for (size_t k = 0; k < (*it)->parents.size(); ++k)
{
if (*(*it)->parents[k] == *vssInstance)
{
already_present = true;
}
}
if (!already_present)
{
(*it)->parents.push_back(vssInstance);
++vssInstance->refcount;
}
}
}
}
++vssInstance->refcount;
component_vss_instances.push_back(vssInstance);
pretty_symlink_struct_writer += "u\n";
++pretty_print_id_add;
}
}
for (size_t j = 0; j < component_vss_instances.size(); ++j)
{
assert(component_vss_instances[j]->refcount>0);
--component_vss_instances[j]->refcount;
if (component_vss_instances[j]->refcount==0)
{
delete component_vss_instances[j];
}
}
if (has_component)
{
SCOPED_DECLARE_FREE_BSTR(componentAsXml);
hr = writerMetadata->SaveAsXML(&componentAsXml);
if (hr != S_OK)
{
VSSLog("Getting component config XML of writer \"" + writerNameStr + "\" failed while indexing. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
return false;
}
std::string utf8Xml = Server->ConvertFromWchar(componentAsXml);
if (!write_file_only_admin(utf8Xml, component_config_dir + os_file_sep() + convert(writerId) + ".xml"))
{
VSSLog("Error writing component config to \"" + component_config_dir + os_file_sep() + convert(writerId) + ".xml\". " + os_last_error_str(), LL_ERROR);
return false;
}
component_config_files.push_back(convert(writerId) + ".xml");
component_config_file_size.push_back(utf8Xml.size());
pretty_symlink_struct += pretty_symlink_struct_writer+"u\n";
++pretty_print_id_add;
}
}
pretty_symlink_struct += "u\n";
++pretty_print_id_add;
addFromLastUpto("windows_components", true, 0, false, outfile);
outfile << pretty_symlink_struct;
file_id += pretty_print_id_add;
addFromLastUpto("windows_components_config", true, 0, false, outfile);
outfile << "d\"windows_components_config\" 0 "
<< getChangeIndicator(Server->getServerWorkingDir() + os_file_sep() + component_config_dir)
<< "#orig_path=" << EscapeParamString("C:\\windows_components_config")<<"\n";
++file_id;
for (size_t i = 0; i < component_config_files.size(); ++i)
{
outfile << "f\"" << component_config_files[i] << "\" " << component_config_file_size[i] << " " << randomChangeIndicator() << "\n";
++file_id;
}
info_json.set("selected_components", selected_components_json);
std::string selected_components_data = info_json.stringify(false);
outfile << "f\"backupcom.xml\" 0 " << randomChangeIndicator() << "\n";
outfile << "f\"info.json\" " << selected_components_data.size() << " " << randomChangeIndicator() << "\n";
file_id+=2;
if (!write_file_only_admin(selected_components_data, component_config_dir + os_file_sep() + "info.json"))
{
VSSLog("Error writing component info to \"" + component_config_dir + os_file_sep() + "info.json\". " + os_last_error_str(), LL_ERROR);
return false;
}
outfile << "u\n";
++file_id;
return true;
}
std::string IndexThread::expandPath(BSTR pathStr)
{
std::vector<wchar_t> tpathRepl(MAX_PATH);
DWORD rc = ExpandEnvironmentStringsW(pathStr, tpathRepl.data(), static_cast<DWORD>(tpathRepl.size()));
if (rc >= tpathRepl.size() || rc == 0)
{
tpathRepl.resize(32768);
VSSLog("Replacing environment strings in path \"" + Server->ConvertFromWchar(pathStr) + "\" failed", LL_ERROR);
return std::string();
}
rc = ExpandEnvironmentStringsW(pathStr, tpathRepl.data(), static_cast<DWORD>(tpathRepl.size()));
if (rc >= tpathRepl.size() || rc == 0)
{
VSSLog("Replacing environment strings in path \"" + Server->ConvertFromWchar(pathStr) + "\" failed", LL_ERROR);
return std::string();
}
return Server->ConvertFromWchar(tpathRepl.data());
}
void IndexThread::removeBackupcomReferences(IVssBackupComponents * backupcom)
{
for (std::map<std::string, SVssInstance*>::iterator it = vss_name_instances.begin();
it != vss_name_instances.end();)
{
std::map<std::string, SVssInstance*>::iterator it_curr = it;
++it;
if (it_curr->second->backupcom == backupcom)
{
--it_curr->second->refcount;
if (it_curr->second->refcount == 0)
{
for (size_t i = 0; i < it_curr->second->parents.size(); ++i)
{
--it_curr->second->parents[i]->refcount;
if (it_curr->second->parents[i]->refcount == 0)
{
delete it_curr->second->parents[i];
}
}
delete it_curr->second;
}
vss_name_instances.erase(it_curr);
}
}
}
bool IndexThread::addFiles(IVssWMFiledesc* wmFile, VSS_ID ssetid, const std::vector<SCRef*>& past_refs, std::string named_prefix, bool use_db,
const std::vector<std::string>& exclude_files, std::fstream &outfile)
{
SCOPED_DECLARE_FREE_BSTR(bPath);
HRESULT hr = wmFile->GetPath(&bPath);
if (hr != S_OK)
{
VSSLog("Getting path of file spec failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
return false;
}
SCOPED_DECLARE_FREE_BSTR(bAltPath);
wmFile->GetAlternateLocation(&bAltPath);
BSTR tpath = bAltPath != NULL ? bAltPath : bPath;
std::string path = removeDirectorySeparatorAtEnd(strlower(expandPath(tpath)));
std::string vol = strlower(getVolPath(path));
std::string orig_path;
if (bAltPath != NULL)
{
orig_path = removeDirectorySeparatorAtEnd(expandPath(bPath));
}
if (vol.empty())
{
VSSLog("Could not determine volume of path \"" + path + "\"", LL_ERROR);
return false;
}
if (!next(path, 0, vol))
{
VSSLog("Path \""+path+"\" does not start with volume \"" + vol + "\"", LL_ERROR);
return false;
}
std::string volpath;
std::string vssvolume;
for (size_t i = 0; i < sc_refs.size(); ++i)
{
if (sc_refs[i]->ssetid == ssetid
&& sc_refs[i]->target == vol)
{
volpath = add_trailing_slash(sc_refs[i]->volpath) + path.substr(vol.size());
vssvolume = sc_refs[i]->volpath;
break;
}
}
if (volpath.empty())
{
VSSLog("Cannot find VSS snapshot for volume \"" + vol + "\"", LL_ERROR);
return false;
}
bool found_backupdir = false;
for (size_t i = 0; i<backup_dirs.size(); ++i)
{
if (backup_dirs[i].group != index_group
&& backup_dirs[i].group!= c_group_vss_components)
continue;
if (backup_dirs[i].symlinked
&& !(index_flags & EBackupDirFlag_FollowSymlinks))
continue;
std::string bpath = addDirectorySeparatorAtEnd(backup_dirs[i].path);
std::string bpath_wo_slash;
bpath = strlower(bpath);
bpath_wo_slash = removeDirectorySeparatorAtEnd(bpath);
if (path == bpath_wo_slash
|| next(path, 0, bpath))
{
if (backup_dirs[i].group == c_group_vss_components)
{
backup_dirs[i].symlinked_confirmed = true;
}
found_backupdir = true;
break;
}
}
if (!found_backupdir)
{
SBackupDir backup_dir;
cd->addBackupDir(named_prefix, path, 0, index_flags, c_group_vss_components, 0);
backup_dir.id = static_cast<int>(db->getLastInsertID());
if (dwt != NULL)
{
std::string msg = "A" + path;
dwt->getPipe()->Write(msg);
}
backup_dir.group = c_group_vss_components;
backup_dir.flags = index_flags;
backup_dir.path = path;
backup_dir.tname = named_prefix;
backup_dir.symlinked = false;
backup_dir.symlinked_confirmed = true;
backup_dir.server_default = index_server_default;
backup_dirs.push_back(backup_dir);
}
SCDirs *scd = getSCDir(named_prefix, index_clientsubname, false);
if (!scd->running)
{
scd->dir = named_prefix;
scd->starttime = Server->getTimeSeconds();
scd->target = path;
scd->orig_target = scd->target;
}
scd->fileserv = true;
bool onlyref = true;
bool stale_shadowcopy = false;
bool shadowcopy_not_configured = false;
if (!start_shadowcopy(scd, &onlyref, true, true, past_refs, false, &stale_shadowcopy, &shadowcopy_not_configured))
{
VSSLog("Starting shadow copy for \"" + named_prefix + "\" failed.", LL_ERROR);
return false;
}
if (!onlyref)
{
VSSLog("Shadow copy for \"" + named_prefix + "\" could not be referenced", LL_ERROR);
return false;
}
if (stale_shadowcopy)
{
VSSLog("Shadow copy for \"" + named_prefix + "\" is stale", LL_ERROR);
return false;
}
if (shadowcopy_not_configured)
{
VSSLog("Shadow copy for \"" + named_prefix + "\" is not configured", LL_ERROR);
return false;
}
scd->running = true;
shareDir(starttoken, named_prefix, volpath);
normalizeVolume(vssvolume);
SCOPED_DECLARE_FREE_BSTR(filespec);
hr = wmFile->GetFilespec(&filespec);
if (hr != S_OK)
{
VSSLog("Getting file spec failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
return false;
}
bool dir_recurse = false;
hr = wmFile->GetRecursive(&dir_recurse);
if (hr == S_FALSE)
{
//Some Database vendor VSS Writer returns this :(
dir_recurse = false;
}
else if (hr != S_OK)
{
VSSLog("Getting recursion flag for file spec failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
return false;
}
std::vector<int> include_depth;
std::vector<std::string> include_prefix;
std::vector<SIndexInclude> include_files = parseIncludePatterns(named_prefix + "\\" + Server->ConvertFromWchar(filespec) + ";"
+ named_prefix + "\\*\\" + Server->ConvertFromWchar(filespec));
if (path.find("127d0a1d-4ef2-11d1-8608-00c04fc295ee") != std::string::npos)
{
int abc = 5;
}
openCbtHdatFile(scd->ref, named_prefix, vol);
initialCheck(vol, vssvolume, path, volpath, named_prefix, outfile, true, index_flags, use_db, false, 0,
dir_recurse, false, exclude_files, include_files, orig_path);
return true;
}
bool IndexThread::getExcludedFiles(IVssExamineWriterMetadata* writerMetadata, UINT nExcludedFiles, std::vector<std::string>& exclude_files)
{
for (UINT k = 0; k < nExcludedFiles; ++k)
{
SCOPED_DECLARE_RELEASE_IUNKNOWN(IVssWMFiledesc, wmFile);
HRESULT hr = writerMetadata->GetExcludeFile(k, &wmFile);
if (hr != S_OK)
{
VSSLog("Error getting excluded file " + convert(k) + " from writer metadata", LL_ERROR);
return false;
}
SCOPED_DECLARE_FREE_BSTR(bPath);
hr = wmFile->GetPath(&bPath);
if (hr != S_OK)
{
VSSLog("Getting path of file excluded spec failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
return false;
}
SCOPED_DECLARE_FREE_BSTR(bAltPath);
wmFile->GetAlternateLocation(&bAltPath);
BSTR tpath = bAltPath != NULL ? bAltPath : bPath;
std::vector<wchar_t> tpathRepl(32768);
DWORD rc = ExpandEnvironmentStringsW(tpath, tpathRepl.data(), static_cast<DWORD>(tpathRepl.size()));
if (rc >= tpathRepl.size() || rc == 0)
{
VSSLog("Replacing environment strings in path \"" + Server->ConvertFromWchar(tpath) + "\" failed", LL_ERROR);
return false;
}
std::string path = Server->ConvertFromWchar(tpathRepl.data());
SCOPED_DECLARE_FREE_BSTR(filespec);
hr = wmFile->GetFilespec(&filespec);
if (hr != S_OK)
{
VSSLog("Getting excluded file spec failed. VSS error code " + GetErrorHResErrStr(hr), LL_ERROR);
return false;
}
if (path.empty())
{
path = Server->ConvertFromWchar(filespec);
}
else
{
if (path.size() > 0 &&
(path[path.size() - 1] == '\\' ||
path[path.size() - 1] == '/'))
{
path += Server->ConvertFromWchar(filespec);
}
else
{
path += os_file_sep() + Server->ConvertFromWchar(filespec);
}
}
strupper(&path);
exclude_files.push_back(sanitizePattern(path));
}
return true;
}
void IndexThread::removeUnconfirmedVssDirs()
{
for (size_t i = 0; i<backup_dirs.size();)
{
if (backup_dirs[i].group == c_group_vss_components)
{
if (!backup_dirs[i].symlinked_confirmed)
{
VSSLog("Removing unconfirmed VSS path \"" + backup_dirs[i].tname + "\" to \"" + backup_dirs[i].path, LL_INFO);
if (dwt != NULL)
{
std::string msg = "D" + backup_dirs[i].path;
dwt->getPipe()->Write(msg);
}
cd->delBackupDir(backup_dirs[i].id);
removeDir(starttoken, backup_dirs[i].tname);
if (filesrv != NULL)
{
filesrv->removeDir(backup_dirs[i].tname, starttoken);
}
backup_dirs.erase(backup_dirs.begin() + i);
continue;
}
}
++i;
}
}