|
|
/*++
Copyright (c) 1999 Microsoft Corporation
Abstract:
@doc @module stswriter.cpp | Implementation of Sharepoint Team Services Writer @end
Author:
Brian Berkowitz [brianb] 08/17/2001
TBD:
Revision History:
Name Date Comments brianb 08/17/2001 created
--*/ #include "stdafx.hxx"
#include "vs_inc.hxx"
#include "vs_reg.hxx"
#include "vssmsg.h"
#include "iadmw.h"
#include "iiscnfg.h"
#include "mdmsg.h"
#include "stssites.hxx"
#include "vswriter.h"
#include "stswriter.h"
#include "vs_seh.hxx"
#include "vs_trace.hxx"
#include "vs_debug.hxx"
#include "bsstring.hxx"
#include "wrtcommon.hxx"
#include "allerror.h"
#include "sqlwrtguid.h"
#include "sqlsnap.h"
////////////////////////////////////////////////////////////////////////
// Standard foo for file name aliasing. This code block must be after
// all includes of VSS header files.
//
#ifdef VSS_FILE_ALIAS
#undef VSS_FILE_ALIAS
#endif
#define VSS_FILE_ALIAS "STSWRTRC"
//
////////////////////////////////////////////////////////////////////////
// writer id
static GUID s_writerId = { 0x4dd6f8dd, 0xbf50, 0x4585, 0x95, 0xde, 0xfb, 0x43, 0x7c, 0x08, 0x31, 0xa6 };
// writer name
static LPCWSTR s_wszWriterName = L"SharepointTSWriter";
STDMETHODCALLTYPE CSTSWriter::~CSTSWriter() { Uninitialize(); delete [] m_rgiSites; delete m_pSites; }
// initialize and subscribe the writer
HRESULT STDMETHODCALLTYPE CSTSWriter::Initialize() { CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSWriter::Initialize");
try { // only initialize the writer if the correct version of sharepoint
// is running on the system
m_pSites = new CSTSSites; if (m_pSites == NULL) ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
if (m_pSites->ValidateSharepointVersion()) { if (!m_pSites->Initialize()) { ft.Throw (VSSDBG_STSWRITER, E_UNEXPECTED, L"Failed to initialize the SharepointTS writer."); } ft.hr = CVssWriter::Initialize ( s_writerId, // writer id
s_wszWriterName, // writer name
VSS_UT_USERDATA, // writer handles user data
VSS_ST_OTHER, // not a database
VSS_APP_FRONT_END, // sql server freezes after us
60000 // 60 second freeze timeout
);
if (ft.HrFailed()) ft.Throw ( VSSDBG_STSWRITER, E_UNEXPECTED, L"Failed to initialize the SharepointTS writer. hr = 0x%08lx", ft.hr );
// subscribe the writer for COM+ events
ft.hr = Subscribe(); if (ft.HrFailed()) ft.Throw ( VSSDBG_STSWRITER, E_UNEXPECTED, L"Subscribing the SharepointTS server writer failed. hr = %0x08lx", ft.hr );
// indicate that th writer is successfully subscribed
m_bSubscribed = true; } } VSS_STANDARD_CATCH(ft)
return ft.hr; }
// uninitialize the writer. This means unsubscribing the writer
HRESULT STDMETHODCALLTYPE CSTSWriter::Uninitialize() { CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSWriter::Uninitialize");
// unsubscribe writer if it is already subscribed
if (m_bSubscribed) return Unsubscribe();
return ft.hr; }
// handle OnPrepareBackup event. Determine whether components selected for
// backup are valid and if so store some metadata in them that is used
// to verify that restore properly restores the sites data to its original
// locations. Keep
bool STDMETHODCALLTYPE CSTSWriter::OnPrepareBackup ( IN IVssWriterComponents *pComponents ) { CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSWriter::OnPrepareBackup");
VSS_PWSZ wszMetadataForSite = NULL;
try { // count of components
UINT cComponents = 0;
// clear array of sites being operated on
delete m_rgiSites; m_rgiSites = NULL; m_cSites = 0;
// determine if we are doing a component or volume based backup
m_bVolumeBackup = !AreComponentsSelected(); if (!m_bVolumeBackup) { // get count of components
ft.hr = pComponents->GetComponentCount(&cComponents); ft.CheckForErrorInternal(VSSDBG_STSWRITER, L"IVssWriterComponents::GetComponentCount");
// allocate array of sites
m_rgiSites = new DWORD[cComponents]; if (m_rgiSites == NULL) ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
// loop through components
for(UINT iComponent = 0; iComponent < cComponents; iComponent++) { // get component
CComPtr<IVssComponent> pComponent; ft.hr = pComponents->GetComponent(iComponent, &pComponent); ft.CheckForErrorInternal(VSSDBG_STSWRITER, L"IVssWriterComponents::GetComponent");
CComBSTR bstrLogicalPath; CComBSTR bstrSiteName;
// get logal path and component name
ft.hr = pComponent->GetLogicalPath(&bstrLogicalPath); ft.CheckForErrorInternal(VSSDBG_STSWRITER, L"IVssComponent::GetLogicalPath");
ft.hr = pComponent->GetComponentName(&bstrSiteName); ft.CheckForErrorInternal(VSSDBG_STSWRITER, L"IVssComponent::GetComponentName");
// logical paths are not supported for STS components
if (bstrLogicalPath && wcslen(bstrLogicalPath) != 0) ft.Throw(VSSDBG_STSWRITER, VSS_E_OBJECT_NOT_FOUND, L"STS components do not have logical paths");
// try parsing the component name as a site name
DWORD iSite; STSSITEPROBLEM problem; if (!ParseComponentName(bstrSiteName, iSite, problem)) ft.Throw(VSSDBG_STSWRITER, VSS_E_OBJECT_NOT_FOUND, L"sites name is not valid");
// see if site is already in array of sites being backed up
for(DWORD iC = 0; iC < iComponent; iC++) { if (m_rgiSites[iC] == iSite) break; }
// if site already exists then throw an error
if (iC < iComponent) ft.Throw(VSSDBG_STSWRITER, VSS_E_OBJECT_ALREADY_EXISTS, L"site backed up twice");
// build backup metadata for site
wszMetadataForSite = BuildSiteMetadata(iSite);
// save backup metadata for site
ft.hr = pComponent->SetBackupMetadata(wszMetadataForSite); ft.CheckForError(VSSDBG_STSWRITER, L"IVssComponent::SetBackupMetadata");
// free allocated metadat for site
CoTaskMemFree(wszMetadataForSite); wszMetadataForSite = NULL;
// save site to be backed up
m_rgiSites[iComponent] = iSite; } }
// number of sites to be backed up is number of components
m_cSites = cComponents; } VSS_STANDARD_CATCH(ft)
// free dangling metadata for site if operation failed
CoTaskMemFree(wszMetadataForSite); TranslateWriterError(ft.hr);
return !ft.HrFailed(); }
// parse a component name to see if it refers to a valid site
// the component name is comment_[instanceId] where comment is
// the server comment for the site and the instance id is the
// IIS instance id
bool CSTSWriter::ParseComponentName ( LPCWSTR wszComponentName, DWORD &iSite, STSSITEPROBLEM &problem ) { CVssFunctionTracer(VSSDBG_STSWRITER, L"CSTSWriter::ParseComponentName");
// pointer to CSTSSites object should already be initialized
BS_ASSERT(m_pSites);
// compute length of component name
DWORD cwc = (DWORD) wcslen(wszComponentName);
// assume site name is properly parsed
problem = STSP_SUCCESS;
// search for last underline site name looks like
// servercomment_instanceid where servercomment is the
// IIS server comment field for the virtual web and instance id
// is the IIS instance id for the virtual web
LPWSTR wszId = wcsrchr(wszComponentName, L'_'); if (wszId == NULL || wcslen(wszId) < 4) return false;
// scan for instance id of site
DWORD siteId; DWORD cFields = swscanf(wszId, L"_[%d]", &siteId); if (cFields == 0) { // if instance id doesn't parse then there is a syntax error
problem = STSP_SYNTAXERROR; return false; }
// get # of sites on the current machine
DWORD cSites = m_pSites->GetSiteCount();
// loop through sites
for(iSite = 0; iSite < cSites; iSite++) { // break out of loop if site id matches
if (m_pSites->GetSiteId(iSite) == siteId) break; }
// if site id is not found then return false
if (iSite == cSites) { problem = STSP_SITENOTFOUND; return false; }
// get site comment
VSS_PWSZ wszComment = m_pSites->GetSiteComment(iSite);
// validate that comment matches prefix of component name
bool bValid = wcslen(wszComment) == cwc - wcslen(wszId) && _wcsnicmp(wszComment, wszComponentName, wcslen(wszComment)) == 0;
// free site comment
CoTaskMemFree(wszComment); if (!bValid) { problem = STSP_SITENAMEMISMATCH; return false; }
// validate that site can be backed up.
return ValidateSiteValidity(iSite, problem); }
// validate site validity to be backed up and restored. This means
// that all files and the database are local to the current machine
bool CSTSWriter::ValidateSiteValidity(DWORD iSite, STSSITEPROBLEM &problem) { CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSWriter::ValidateSiteValidity");
BS_ASSERT(m_pSites);
// co task strings that need to be freed if function throws
VSS_PWSZ wszDsn = NULL; VSS_PWSZ wszContentRoot = NULL; VSS_PWSZ wszConfigRoot = NULL;
try { // get dsn for site
wszDsn = m_pSites->GetSiteDSN(iSite); LPWSTR wszServer, wszInstance, wszDb;
// parse the dsn into server name, instance name and database name
if (!ParseDsn(wszDsn, wszServer, wszInstance, wszDb)) { // site DSN is invalid
problem = STSP_SITEDSNINVALID; CoTaskMemFree(wszDsn); return false; }
// verify that the server is local
if (!ValidateServerIsLocal(wszServer)) { problem = STSP_SQLSERVERNOTLOCAL; CoTaskMemFree(wszDsn); return false; }
// free up dsn. we are done with it
CoTaskMemFree(wszDsn); wszDsn = NULL;
// get content root of the site
wszContentRoot = m_pSites->GetSiteRoot(iSite);
// validate that path to root is on the local machine
if (!ValidatePathIsLocal(wszContentRoot)) { problem = STSP_CONTENTNOTLOCAL; CoTaskMemFree(wszContentRoot); return false; }
// free up content root
CoTaskMemFree(wszContentRoot); wszContentRoot = NULL;
// get configuration root of the site
wszConfigRoot = m_pSites->GetSiteRoles(iSite);
// validate that configuration path is local
if (!ValidatePathIsLocal(wszConfigRoot)) { problem = STSP_CONFIGNOTLOCAL; CoTaskMemFree(wszConfigRoot); return false; }
// free up configuration root
CoTaskMemFree(wszConfigRoot); return true; } catch(...) { // free allocated memory and rethrow error
CoTaskMemFree(wszDsn); CoTaskMemFree(wszContentRoot); CoTaskMemFree(wszConfigRoot); throw; } }
// build metadata for the site
// the metadata is used to validate that the site can be restored properly
// it consists of the content root of the site, the configuration root
// of the site, and the sql database. All need to match
VSS_PWSZ CSTSWriter::BuildSiteMetadata(DWORD iSite) { CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSWriter::BuildSiteMetadata");
BS_ASSERT(m_pSites);
// co task allocated strings that need to be freed if the function throws
VSS_PWSZ wszDsn = NULL; VSS_PWSZ wszContentRoot = NULL; VSS_PWSZ wszConfigRoot = NULL; VSS_PWSZ wszMetadata = NULL; try { // get dsn for site
wszDsn = m_pSites->GetSiteDSN(iSite); LPWSTR wszInstance, wszDb, wszServer;
// break dsn into server, instance, and database names
if (!ParseDsn(wszDsn, wszServer, wszInstance, wszDb)) { // since we already parsed the dsn once, we don't expect
// parsing it to fail when we try a second time
BS_ASSERT(FALSE && L"shouldn't get here"); ft.Throw(VSSDBG_STSWRITER, E_UNEXPECTED, L"unexpected failure parsing the DSN"); }
// get the content root of the site
wszContentRoot = m_pSites->GetSiteRoot(iSite);
// get the configuration path for the site
wszConfigRoot = m_pSites->GetSiteRoles(iSite);
// compute size of metadata string. the format of the string is
// servername\instancename1111dbname2222siteroot3333configroot where
// 1111 is the length fo the database name, 2222 is the length of the site
// root, and 3333 is the length of th econfiguration root. The lengths
// are all 4 digit hex numbers
DWORD cwc = (DWORD) ((wszServer ? wcslen(wszServer) : 0) + (wszInstance ? wcslen(wszInstance) : 0) + wcslen(wszDb) + wcslen(wszContentRoot) + wcslen(wszConfigRoot) + (3 * 4) + 3); wszMetadata = (VSS_PWSZ) CoTaskMemAlloc(cwc * sizeof(WCHAR)); if (wszMetadata == NULL) ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
// create server and instance parts of path
if (wszServer && wszInstance) swprintf(wszMetadata, L"%s\\%s", wszServer, wszInstance); else if (wszServer) swprintf(wszMetadata, L"%s\\", wszServer); else if (wszInstance) wcscpy(wszMetadata, wszInstance);
// include database name, site root, and configuration root
swprintf ( wszMetadata + wcslen(wszMetadata), L";%04x%s%04x%s%04x%s", wcslen(wszDb), wszDb, wcslen(wszContentRoot), wszContentRoot, wcslen(wszConfigRoot), wszConfigRoot );
// free up dsn, config root and content root
CoTaskMemFree(wszDsn); CoTaskMemFree(wszConfigRoot); CoTaskMemFree(wszContentRoot); return wszMetadata; } catch(...) { // free memory and rethrow error
CoTaskMemFree(wszDsn); CoTaskMemFree(wszConfigRoot); CoTaskMemFree(wszContentRoot); CoTaskMemFree(wszMetadata); throw; } }
// determine if a database is on a snapshotted device. If it is partially
// on a snapshotted device throw VSS_E_WRITERERROR_INCONSISTENTSNAPSHOT
bool CSTSWriter::IsDatabaseAffected(LPCWSTR wszInstance, LPCWSTR wszDb) { CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSWriter::IsDatabaseAffected"); CSqlEnumerator *pEnumServers = NULL; CSqlEnumerator *pEnumDatabases = NULL; CSqlEnumerator *pEnumFiles = NULL; try { ServerInfo server; DatabaseInfo database; DatabaseFileInfo file;
// create enumerator for sql server instances
pEnumServers = CreateSqlEnumerator(); if (pEnumServers == NULL) ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"Failed to create CSqlEnumerator");
// find first server
ft.hr = pEnumServers->FirstServer(&server); while(ft.hr != DB_S_ENDOFROWSET) { // check for error code
if (ft.HrFailed()) ft.Throw ( VSSDBG_STSWRITER, E_UNEXPECTED, L"Enumerating database servers failed. hr = 0x%08lx", ft.hr );
if (server.isOnline && (wszInstance == NULL && wcslen(server.name) == 0) || _wcsicmp(server.name, wszInstance) == 0) { // if instance name matches, then try finding the
// database by creating the database enumerator
pEnumDatabases = CreateSqlEnumerator(); if (pEnumDatabases == NULL) ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"Failed to create CSqlEnumerator");
// find first database
ft.hr = pEnumDatabases->FirstDatabase(server.name, &database); while(ft.hr != DB_S_ENDOFROWSET) { // check for error
if (ft.HrFailed()) ft.Throw ( VSSDBG_GEN, E_UNEXPECTED, L"Enumerating databases failed. hr = 0x%08lx", ft.hr );
// if database name matches. then scan files
// to see what volumes they are on
if (_wcsicmp(database.name, wszDb) == 0 && database.supportsFreeze) { bool fAffected = false; DWORD cFiles = 0;
// recreate enumerator for files
BS_ASSERT(pEnumFiles == NULL); pEnumFiles = CreateSqlEnumerator(); if (pEnumFiles == NULL) ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"Failed to create CSqlEnumerator");
// findfirst database file
ft.hr = pEnumFiles->FirstFile(server.name, database.name, &file); while(ft.hr != DB_S_ENDOFROWSET) { // check for error
if (ft.HrFailed()) ft.Throw ( VSSDBG_GEN, E_UNEXPECTED, L"Enumerating database files failed. hr = 0x%08lx", ft.hr );
// determine if database file is included in the
// backup
if (IsPathAffected(file.name)) { // if it is and other files aren't then
// the snapshot is inconsistent
if (!fAffected && cFiles > 0) ft.Throw(VSSDBG_STSWRITER, HRESULT_FROM_WIN32(E_SQLLIB_TORN_DB), L"some database files are snapshot and some aren't");
fAffected = true; } else { // if it isn't and other files are, then
// the snapshot is inconsistent
if (fAffected) ft.Throw(VSSDBG_STSWRITER, HRESULT_FROM_WIN32(E_SQLLIB_TORN_DB), L"some database files are snapshot and some aren't"); }
// continue at next file
ft.hr = pEnumFiles->NextFile(&file); cFiles++; }
delete pEnumFiles; pEnumFiles = NULL; delete pEnumDatabases; pEnumDatabases = NULL; delete pEnumServers; pEnumServers = NULL; return fAffected; }
// continue at next database
ft.hr = pEnumDatabases->NextDatabase(&database); }
// done with database enumerator
delete pEnumDatabases; pEnumDatabases = NULL; }
// continue at next server
ft.hr = pEnumServers->NextServer(&server); }
ft.Throw(VSSDBG_STSWRITER, E_UNEXPECTED, L"database is not found %s\\%s", server.name, database.name); } catch(...) { // delete enumerators and rethrow error
delete pEnumFiles; delete pEnumServers; delete pEnumDatabases; throw; }
// we won't really ever get here. This is just to keep the compiler
// happy
return false; }
// determine if a site is completely contained in the set of volumes being
// snapshotted. If it is partially contained then throw
// VSS_E_WRITERERROR_INCONSISTENTSNAPSHOT.
bool CSTSWriter::IsSiteSnapshotted(DWORD iSite) { CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSWriter::IsSiteSnapshotted");
BS_ASSERT(m_pSites);
// co task allocated strings that need to be freed
// in the case of a failure
VSS_PWSZ wszDsn = NULL; VSS_PWSZ wszContentRoot = NULL; VSS_PWSZ wszConfigRoot = NULL; VSS_PWSZ wszInstanceName = NULL;
try { // get dsn for site
wszDsn = m_pSites->GetSiteDSN(iSite);
// get content root for the site
wszContentRoot = m_pSites->GetSiteRoot(iSite);
// gt configuration root for the site
wszConfigRoot = m_pSites->GetSiteRoles(iSite); LPWSTR wszServer, wszInstance, wszDb;
// parse the site dsn into server, instance, and database
if (!ParseDsn(wszDsn, wszServer, wszInstance, wszDb)) { // shouldn't get here since we previously parsed
// the site's dsn
BS_ASSERT(FALSE && L"shouldn't get here"); ft.Throw(VSSDBG_STSWRITER, E_UNEXPECTED, L"dsn is invalid"); }
// compute instance name as server\\instance
wszInstanceName = (VSS_PWSZ) CoTaskMemAlloc(((wszServer ? wcslen(wszServer) : 0) + (wszInstance ? wcslen(wszInstance) : 0) + 2) * sizeof(WCHAR)); if (wszInstanceName == NULL) ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
if (wszServer) { wcscpy(wszInstanceName, wszServer); wcscat(wszInstanceName, L"\\"); if (wszInstance) wcscat(wszInstanceName, wszInstance); } else if (wszInstance) wcscpy(wszInstanceName, wszInstance); else wszInstanceName[0] = L'\0';
// determine if database is snapshotted
bool bDbAffected = IsDatabaseAffected(wszInstanceName, wszDb);
// determine if content root is snapshotted
bool bContentAffected = IsPathAffected(wszContentRoot);
// determine if configuration root is snapshotted
bool bConfigAffected = IsPathAffected(wszConfigRoot);
// free up memory for dsn, content root, and configuration root
CoTaskMemFree(wszDsn); CoTaskMemFree(wszContentRoot); CoTaskMemFree(wszConfigRoot); wszDsn = NULL; wszContentRoot = NULL; wszConfigRoot = NULL;
if (bDbAffected && bContentAffected && bConfigAffected) // if all are snapshotted then return true
return true; else if (bDbAffected || bContentAffected || bConfigAffected) // if some but not all are snapshotted, then indicate
// the inconsistency
ft.Throw ( VSSDBG_STSWRITER, VSS_E_WRITERERROR_INCONSISTENTSNAPSHOT, L"site %d partially affected by snapshot", m_pSites->GetSiteId(iSite) ); else // if none are snapshotted, then return false
return false; } catch(...) { // free memory and rethrow exception
CoTaskMemFree(wszDsn); CoTaskMemFree(wszConfigRoot); CoTaskMemFree(wszContentRoot); CoTaskMemFree(wszInstanceName); throw; }
// will not get here. Just here to keep the compiler happy
return false; }
// lockdown all sites that are on volumes being snapshotted. If any sites
// are both on volumes being snapshotted and not being snapshot then
// indicate tht the snapshot is inconsistent. If the quota database is
// on a volume being snapshoted then lock it as well
void CSTSWriter::LockdownAffectedSites() { CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSWriter::LockdownAffectedSites");
// co task string that needs to be freed in the case of exception
VSS_PWSZ wszQuotaDbPath = NULL; BS_ASSERT(m_pSites);
try { // determine if bootable system state is not being backed up. If so,
// then the quota database is locked if its path is being snapshotted.
// if bootable system state is already being backed up, the the
// quota database is already locked
if (!IsBootableSystemStateBackedUp()) { // determine if quota database is being snapshotted
wszQuotaDbPath = m_pSites->GetQuotaDatabase(); if (IsPathAffected(wszQuotaDbPath)) // if so then lock it
m_pSites->LockQuotaDatabase();
// free memory for quota db path
CoTaskMemFree(wszQuotaDbPath); wszQuotaDbPath = NULL; }
// get count of sites
DWORD cSites = m_pSites->GetSiteCount();
// loop through sites
for(DWORD iSite = 0; iSite < cSites; iSite++) { // if site is snapshotted lock it
if (IsSiteSnapshotted(iSite)) m_pSites->LockSiteContents(iSite); } } catch(...) { // free memory and rethrow error
CoTaskMemFree(wszQuotaDbPath); throw; } }
// handle prepare snapshot event. Lock any sites that need to be
// locked based on components document or on volumes being snapshotted
bool STDMETHODCALLTYPE CSTSWriter::OnPrepareSnapshot() { CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSWriter::OnPrepareSnapshot");
BS_ASSERT(m_pSites);
try { // lock quota database if bootable system state is being backed up
if (IsBootableSystemStateBackedUp()) m_pSites->LockQuotaDatabase();
if (m_bVolumeBackup) // if volume backup, then lock sites based on whether they
// are fully on the snapshotted volumes.
LockdownAffectedSites(); else { // loop through sites being backed up
for (DWORD i = 0; i < m_cSites; i++) { DWORD iSite = m_rgiSites[i];
// validate that site is on volumes being snapshotted
if (!IsSiteSnapshotted(iSite)) // the site is in selected to be backed up. it should
// be snapshotted as well
ft.Throw ( VSSDBG_STSWRITER, VSS_E_WRITERERROR_INCONSISTENTSNAPSHOT, L"a site is selected but is on volumes that are not snapshot" );
// lock site
m_pSites->LockSiteContents(iSite); } }
} VSS_STANDARD_CATCH(ft)
if (ft.HrFailed()) { // unlock anything that was locked if operation fails
m_pSites->UnlockSites(); m_pSites->UnlockQuotaDatabase(); TranslateWriterError(ft.hr); }
return !ft.HrFailed(); }
// freeze operation. Nothing is done here since all the work is done
// during the prepare phase
bool STDMETHODCALLTYPE CSTSWriter::OnFreeze() { CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSWriter::OnFreeze"); return true; }
// unlock everything at thaw
bool STDMETHODCALLTYPE CSTSWriter::OnThaw() { CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSWriter::OnThaw");
BS_ASSERT(m_pSites);
m_pSites->UnlockSites(); m_pSites->UnlockQuotaDatabase(); return true; }
// unlock everything at abort
bool STDMETHODCALLTYPE CSTSWriter::OnAbort() { CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSWriter::OnAbort");
BS_ASSERT(m_pSites);
m_pSites->UnlockQuotaDatabase(); m_pSites->UnlockSites(); return true; }
// prefix for dsn strings as stored in registry
static LPCWSTR s_wszDsnPrefix = L"Provider=sqloledb;Server=";
// separtor between fields in DSN string
const WCHAR x_wcDsnSeparator = L';';
// prefix for database name
static LPCWSTR s_wszDsnDbPrefix = L";Database="; const DWORD x_cwcWriterIdPrefix = 32 + 2 + 4 + 1; // 32 nibbles + 2 braces + 4 dashes + 1 colon
// {12345678-1234-1234-1234-123456789abc}:
// check validity of dsn and break it up into its components.
bool CSTSWriter::ParseDsn ( LPWSTR wszDsn, LPWSTR &wszServer, // server name [out]
LPWSTR &wszInstance, // instance name [out]
LPWSTR &wszDb // database name [out]
) { // check validity of beginning of dsn
if (wcslen(wszDsn) <= wcslen(s_wszDsnPrefix) || _wcsnicmp(wszDsn, s_wszDsnPrefix, wcslen(s_wszDsnPrefix)) != 0) return false;
// skip to start of server name
wszServer = wszDsn + wcslen(s_wszDsnPrefix);
// search for next semicolon which is the start of the database name
LPWSTR wszDbSection = wcschr(wszServer, x_wcDsnSeparator);
// if not found, then dsn is invalid
if (wszServer == NULL) return false;
// make sure form of name is Database=foo
if (wcslen(wszDbSection) <= wcslen(s_wszDsnDbPrefix) || _wcsnicmp(wszDbSection, s_wszDsnDbPrefix, wcslen(s_wszDsnDbPrefix)) != 0) return false;
// skip to beginning of database name
wszDb = wszDbSection + wcslen(s_wszDsnDbPrefix); if (wcslen(wszDb) == 0) return false;
// setup separator for server name, i.e., null out the semicolon
// before the Database=...
*wszDbSection = L'\0';
// search for instance name. Server name is form machine\instance
wszInstance = wcschr(wszServer, L'\\'); if (wszInstance != NULL) { // null out server name and update instance pointer
// to point after backslash
*wszInstance = L'\0'; wszInstance++;
// set instance to NULL if it is 0 length
if (wcslen(wszInstance) == 0) wszInstance = NULL; }
return true; }
// handle request for WRITER_METADATA
// implements CVssWriter::OnIdentify
bool STDMETHODCALLTYPE CSTSWriter::OnIdentify(IVssCreateWriterMetadata *pMetadata) { CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSWriter::OnIdentify");
BS_ASSERT(m_pSites);
// co task strings that need to be freed if exception is thrown
VSS_PWSZ wszSiteName = NULL; VSS_PWSZ wszComponentName = NULL; VSS_PWSZ wszDsn = NULL; VSS_PWSZ wszContentRoot = NULL; VSS_PWSZ wszConfigRoot = NULL; VSS_PWSZ wszDbComponentPath = NULL; try { // setup restore method to restore if can replace
ft.hr = pMetadata->SetRestoreMethod ( VSS_RME_RESTORE_IF_CAN_REPLACE, NULL, NULL, VSS_WRE_ALWAYS, false );
ft.CheckForErrorInternal(VSSDBG_STSWRITER, L"IVssCreateWriterMetadata::SetRestoreMethod");
// loop through sites adding one component for each site
DWORD cSites = m_pSites->GetSiteCount(); for(DWORD iSite = 0; iSite < cSites; iSite++) { do { // component name is server comment concatenated with
// _[instance id] so if server comment for site is foo
// and the instance id is 69105 then the component
// name is foo_[69105]
//
DWORD siteId = m_pSites->GetSiteId(iSite); wszSiteName = m_pSites->GetSiteComment(iSite); WCHAR buf[32]; swprintf(buf, L"_[%d]", siteId);
// allocate string for component name
wszComponentName = (VSS_PWSZ) CoTaskMemAlloc((wcslen(wszSiteName) + wcslen(buf) + 1) * sizeof(WCHAR)); if (wszComponentName == NULL) ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
// construct component name
wcscpy(wszComponentName, wszSiteName); wcscat(wszComponentName, buf);
// get site dsn and parse it
wszDsn = m_pSites->GetSiteDSN(iSite); LPWSTR wszServer, wszDb, wszInstance;
// if site dsn is not valid, then skip component
if (!ParseDsn(wszDsn, wszServer, wszInstance, wszDb)) continue;
// only include component if server name refers to the
// local machine
bool bServerIsLocal = ValidateServerIsLocal(wszServer);
// compute size of funky file name for database component
DWORD cwcDbComponentPath = (DWORD) (wszServer ? wcslen(wszServer) : 0) + 2 + x_cwcWriterIdPrefix; if (wszInstance) cwcDbComponentPath += (DWORD) wcslen(wszInstance) + 1;
// allocate component name
wszDbComponentPath = (VSS_PWSZ) CoTaskMemAlloc(cwcDbComponentPath * sizeof(WCHAR)); if (wszDbComponentPath == NULL) ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
// fill in component path name
// {sql id}:server\instance or
// {sql id}:server\ or
// {sql id}:\instance or
// {sql id}:\ //
if (wszServer && wszInstance) swprintf ( wszDbComponentPath, WSTR_GUID_FMT L":\\%s\\%s", GUID_PRINTF_ARG(WRITERID_SqlWriter), wszServer, wszInstance ); else if (wszServer && wszInstance == NULL) swprintf ( wszDbComponentPath, WSTR_GUID_FMT L":\\%s\\", GUID_PRINTF_ARG(WRITERID_SqlWriter), wszServer ); else if (wszInstance) swprintf ( wszDbComponentPath, WSTR_GUID_FMT L":\\%s", GUID_PRINTF_ARG(WRITERID_SqlWriter), wszInstance ); else swprintf ( wszDbComponentPath, WSTR_GUID_FMT L":\\", GUID_PRINTF_ARG(WRITERID_SqlWriter) );
// get content root of the site
wszContentRoot = m_pSites->GetSiteRoot(iSite); bool bContentIsLocal = ValidatePathIsLocal(wszContentRoot);
// get configuration root of the site
wszConfigRoot = m_pSites->GetSiteRoles(iSite);
bool bConfigIsLocal = ValidatePathIsLocal(wszConfigRoot); bool bNonLocal = !bServerIsLocal || !bContentIsLocal || !bConfigIsLocal;
// add component to medatadata. comment indicates
// whether site is local or not. Non-local sites may not
// be backed up
ft.hr = pMetadata->AddComponent ( VSS_CT_FILEGROUP, // component type
NULL, // logical path
wszComponentName, // component name
bNonLocal ? L"!!non-local-site!!" : NULL, // caption
NULL, // icon
0, // length of icon
TRUE, // restore metadata
FALSE, // notify on backup complete
TRUE // selectable
);
ft.CheckForErrorInternal(VSSDBG_STSWRITER, L"IVssCreateWriterMetadata::AddComponent");
// add database as recursive component
ft.hr = pMetadata->AddFilesToFileGroup ( NULL, wszComponentName, wszDbComponentPath, wszDb, false, NULL );
ft.CheckForErrorInternal(VSSDBG_STSWRITER, L"IVssCreateWriterMetadata::AddFilesToFileGroup");
// add all files under the content root
ft.hr = pMetadata->AddFilesToFileGroup ( NULL, wszComponentName, wszContentRoot, L"*", true, NULL );
ft.CheckForErrorInternal(VSSDBG_STSWRITER, L"IVssCreateWriterMetadata::AddFilesToFileGroup");
// add all files under the appropriate directory in
// Documents and Settings
ft.hr = pMetadata->AddFilesToFileGroup ( NULL, wszComponentName, wszConfigRoot, L"*", true, NULL );
ft.CheckForErrorInternal(VSSDBG_STSWRITER, L"IVssCreateWriterMetadata::AddFilesToFileGroup"); } while(FALSE);
// free up memory allocated in this iteration
VssFreeString(wszContentRoot); VssFreeString(wszConfigRoot); VssFreeString(wszDbComponentPath); VssFreeString(wszDsn); VssFreeString(wszComponentName); VssFreeString(wszSiteName); } } VSS_STANDARD_CATCH(ft)
// free up memory in case of failure
VssFreeString(wszContentRoot); VssFreeString(wszConfigRoot); VssFreeString(wszDbComponentPath); VssFreeString(wszDsn); VssFreeString(wszComponentName); VssFreeString(wszSiteName);
if (ft.HrFailed()) { TranslateWriterError(ft.hr); return false; }
return true; }
// translate a sql writer error code into a writer error
void CSTSWriter::TranslateWriterError(HRESULT hr) { switch(hr) { default: // all other errors are treated as non-retryable
SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE); break;
case S_OK: break;
case E_OUTOFMEMORY: case HRESULT_FROM_WIN32(ERROR_DISK_FULL): case HRESULT_FROM_WIN32(ERROR_TOO_MANY_OPEN_FILES): case HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY): case HRESULT_FROM_WIN32(ERROR_NO_MORE_USER_HANDLES): // out of resource errors
SetWriterFailure(VSS_E_WRITERERROR_OUTOFRESOURCES); break;
case VSS_E_WRITERERROR_INCONSISTENTSNAPSHOT: case E_SQLLIB_TORN_DB: case VSS_E_OBJECT_NOT_FOUND: case VSS_E_OBJECT_ALREADY_EXISTS: // inconsistencies and other errors by the requestor
SetWriterFailure(VSS_E_WRITERERROR_INCONSISTENTSNAPSHOT); break; } }
// handle pre restore event
bool STDMETHODCALLTYPE CSTSWriter::OnPreRestore ( IN IVssWriterComponents *pWriter ) { CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSWriter::OnPreRestore");
BS_ASSERT(m_pSites);
// co task allocated strings that need to be freed if an
// exception is thrown
VSS_PWSZ wszMetadataForSite = NULL; VSS_PWSZ wszContentRoot = NULL;
// component is at toplevel scope since it will be used to set
// failure message in failure case
CComPtr<IVssComponent> pComponent;
try { UINT cComponents; ft.hr = pWriter->GetComponentCount(&cComponents); ft.CheckForErrorInternal(VSSDBG_STSWRITER, L"IVssWriterComponents::GetComponentCount");
// if no components, then just return immediately
if (cComponents == 0) return true;
// loop through components
for(UINT iComponent = 0; iComponent < cComponents; iComponent++) { ft.hr = pWriter->GetComponent(iComponent, &pComponent); ft.CheckForErrorInternal(VSSDBG_STSWRITER, L"IVssWriterComponents::GetComponent");
bool bSelectedForRestore; ft.hr = pComponent->IsSelectedForRestore(&bSelectedForRestore); ft.CheckForErrorInternal(VSSDBG_STSWRITER, L"IVssComponent::IsSelectedForRestore");
if (!bSelectedForRestore) { // if component is not selected for restore, then
// skip it
pComponent = NULL; continue; }
// validate component type
VSS_COMPONENT_TYPE ct; ft.hr = pComponent->GetComponentType(&ct); ft.CheckForErrorInternal(VSSDBG_STSWRITER, L"IVssComponent::GetComponentType");
if (ct != VSS_CT_FILEGROUP) ft.Throw(VSSDBG_STSWRITER, VSS_E_WRITERERROR_NONRETRYABLE, L"requesting a non-database component");
CComBSTR bstrLogicalPath; CComBSTR bstrComponentName;
ft.hr = pComponent->GetLogicalPath(&bstrLogicalPath); ft.CheckForErrorInternal(VSSDBG_STSWRITER, L"IVssComponent::GetLogicalPath");
// validate that no logical path is provided
if (bstrLogicalPath && wcslen(bstrLogicalPath) != 0) ft.Throw(VSSDBG_STSWRITER, VSS_E_OBJECT_NOT_FOUND, L"STS components do not have logical paths");
// get component name
ft.hr = pComponent->GetComponentName(&bstrComponentName); ft.CheckForErrorInternal(VSSDBG_STSWRITER, L"IVssComponent::GetComponentName"); DWORD iSite; STSSITEPROBLEM problem;
// validate that the component name is valid
if (!ParseComponentName(bstrComponentName, iSite, problem)) SetSiteInvalid(pComponent, bstrComponentName, problem);
// build metadata for the site
wszMetadataForSite = BuildSiteMetadata(iSite); CComBSTR bstrMetadataForComponent;
// get metadata for site saved when the site was backed up
ft.hr = pComponent->GetBackupMetadata(&bstrMetadataForComponent); ft.CheckForErrorInternal(VSSDBG_STSWRITER, L"IVssComponent::GetBackupMetadata");
// validate that metadata is identical. If not, then figure
// out what changed
if (_wcsicmp(wszMetadataForSite, bstrMetadataForComponent) != 0) SetSiteMetadataMismatch(pComponent, bstrMetadataForComponent, wszMetadataForSite);
// get content root for site
wszContentRoot = m_pSites->GetSiteRoot(iSite);
// try emptying contents from the content root
ft.hr = RemoveDirectoryTree(wszContentRoot); if (ft.HrFailed()) SetRemoveFailure(pComponent, wszContentRoot, ft.hr);
// set component to null in preparation of moving to next
// component
pComponent = NULL; } } VSS_STANDARD_CATCH(ft)
CoTaskMemFree(wszContentRoot); CoTaskMemFree(wszMetadataForSite); if (ft.HrFailed() && pComponent != NULL) SetPreRestoreFailure(pComponent, ft.hr);
return !ft.HrFailed(); }
// indicate that a site cannot be restored because the site referred to is invalid
void CSTSWriter::SetSiteInvalid ( IVssComponent *pComponent, LPCWSTR wszSiteName, STSSITEPROBLEM problem ) { CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSWriter::SetSiteInvalid");
WCHAR buf[512]; LPCWSTR wszSiteError;
switch(problem) { default: case STSP_SYNTAXERROR: wszSiteError = L"Syntax error in site name"; break;
case STSP_SITENOTFOUND: wszSiteError = L"Site does not exist on this machine"; break;
case STSP_SITENAMEMISMATCH: wszSiteError = L"Site name does not match the server comment for the IIS Web Server: "; break;
case STSP_SITEDSNINVALID: wszSiteError = L"Site has an invalid Database DSN: "; break;
case STSP_SQLSERVERNOTLOCAL: wszSiteError = L"Database for the site is not local: "; break;
case STSP_CONTENTNOTLOCAL: wszSiteError = L"IIS Web Server root is not local: "; break;
case STSP_CONFIGNOTLOCAL: wszSiteError = L"Sharepoint Site Configuration is not local: "; break; }
wcscpy(buf, L"Problem with site specified in component -- "); wcscat(buf, wszSiteError); if (wcslen(wszSiteName) < 256) wcscat(buf, wszSiteName); else { DWORD cwc = (DWORD) wcslen(buf); memcpy(buf + cwc, wszSiteName, 256 * sizeof(WCHAR)); *(buf + cwc + 256) = L'\0'; wcscat(buf, L"..."); }
pComponent->SetPreRestoreFailureMsg(buf); SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE); ft.Throw(VSSDBG_STSWRITER, VSS_E_WRITERERROR_NONRETRYABLE, L"site can't be restored"); }
// indicate that a site cannot be restored because its DSN, content,
// or config roots mismatch
void CSTSWriter::SetSiteMetadataMismatch ( IVssComponent *pComponent, LPWSTR wszMetadataBackup, LPWSTR wszMetadataRestore ) { CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSWriter::SetSiteMetadataMismatch");
// seach for end of server name in metadata
LPWSTR pwcB = wcschr(wszMetadataBackup, L';'); LPWSTR pwcR = wcschr(wszMetadataRestore, L';'); try { if (pwcB == NULL) ft.Throw(VSSDBG_STSWRITER, VSS_ERROR_CORRUPTXMLDOCUMENT_MISSING_ATTRIBUTE, L"backup metadata is corrupt");
BS_ASSERT(pwcR != NULL);
// compute size of server name
DWORD cwcB = (DWORD) (pwcB - wszMetadataBackup); DWORD cwcR = (DWORD) (pwcR - wszMetadataRestore); do { if (cwcB != cwcR || _wcsnicmp(wszMetadataBackup, wszMetadataRestore, cwcB) != 0) { // server/instance name differs
LPWSTR wsz = new WCHAR[cwcB + cwcR + 256]; if (wsz == NULL) // memory allocation failure, just try saving a simple error message
pComponent->SetPreRestoreFailureMsg(L"Mismatch between backup and restore [Server/Instance]."); else { // indicate that server/instance name mismatches
wcscpy(wsz, L"Mismatch between backup and restore[Server/Instance]: Backup="); DWORD cwc1 = (DWORD) wcslen(wsz);
// copy in server/instance from backup components document
memcpy(wsz + cwc1, wszMetadataBackup, cwcB * sizeof(WCHAR)); wsz[cwc1 + cwcB] = L'\0';
// copy in server/instance from current site
wcscat(wsz, L", Restore="); cwc1 = (DWORD) wcslen(wsz); memcpy(wsz + cwc1, wszMetadataRestore, cwcR * sizeof(WCHAR)); wsz[cwc1 + cwcR] = L'\0'; pComponent->SetPreRestoreFailureMsg(wsz); delete wsz; }
continue; }
pwcB++; pwcR++; if (!compareNextMetadataString ( pComponent, pwcB, pwcR, L"Sharepoint database name" )) continue;
if (!compareNextMetadataString ( pComponent, pwcB, pwcR, L"IIS Web site root" )) continue;
compareNextMetadataString ( pComponent, pwcB, pwcR, L"Sharepoint site configuration" ); }while (false); } VSS_STANDARD_CATCH(ft)
if (ft.hr == VSS_ERROR_CORRUPTXMLDOCUMENT_MISSING_ATTRIBUTE) { // indication that the backup metadata is corrupt
WCHAR *pwcT = new WCHAR[64 + wcslen(wszMetadataBackup)]; if (pwcT == NULL) pComponent->SetPreRestoreFailureMsg(L"Backup metadata is corrupt."); else { // if we are able to allocate room for metadata, then include it
// in string
wcscpy(pwcT, L"Backup metadata is corrupt. Metadata = "); wcscat(pwcT, wszMetadataBackup); pComponent->SetPreRestoreFailureMsg(pwcT); delete pwcT; } }
// indicate that the error is not-retryable since the site has changed
SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE); ft.Throw(VSSDBG_STSWRITER, VSS_E_WRITERERROR_NONRETRYABLE, L"site can't be restored"); }
// compare a component of the metadata string. Each component begins
// with a 4 digit hex number which is the length of the component string
// that follows.
bool CSTSWriter::compareNextMetadataString ( IVssComponent *pComponent, LPWSTR &pwcB, LPWSTR &pwcR, LPCWSTR wszMetadataComponent ) { CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSWriter::compareNextMetadataString"); DWORD cwcB, cwcR; if (swscanf(pwcB, L"%04x", &cwcB) != 1) ft.Throw(VSSDBG_STSWRITER, VSS_ERROR_CORRUPTXMLDOCUMENT_MISSING_ATTRIBUTE, L"invalid backup metadata");
BS_VERIFY(swscanf(pwcR, L"%04x", &cwcR) == 1); if (cwcR != cwcB || _wcsnicmp(pwcB + 4, pwcR + 4, cwcB) != 0) { LPWSTR wsz = new WCHAR[cwcB + cwcR + wcslen(wszMetadataComponent) + 256]; if (wsz == NULL) { WCHAR buf[256]; swprintf(buf, L"Mismatch between backup and restore[%s]", wszMetadataComponent); pComponent->SetPreRestoreFailureMsg(buf); } else { swprintf(wsz, L"Mismatch between backup and restore[%s]: Backup=", wszMetadataComponent); DWORD cwc1 = (DWORD) wcslen(wsz);
// copy in backup component value
memcpy(wsz + cwc1, pwcB + 4, cwcB * sizeof(WCHAR)); wsz[cwc1 + cwcB] = L'\0'; wcscat(wsz, L", Restore="); cwc1 = (DWORD) wcslen(wsz);
// copy in restore component value
memcpy(wsz + cwc1, pwcR + 4, cwcR * sizeof(WCHAR)); wsz[cwc1 + cwcR] = L'\0'; pComponent->SetPreRestoreFailureMsg(wsz); delete wsz; }
return false; }
// skip past component name
pwcB += 4 + cwcB; pwcR += 4 + cwcR; return true; }
// indicate that a site could not be restored because its content root
// could not be completely deleted.
void CSTSWriter::SetRemoveFailure ( IVssComponent *pComponent, LPCWSTR wszContentRoot, HRESULT hr ) { CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSWriter::SetRemoveFailure");
WCHAR buf[256];
wprintf(buf, L"PreRestore failed due to error removing files from the IIS Web Site Root %s due to error: hr = 0x%08lx", wszContentRoot, hr); pComponent->SetPreRestoreFailureMsg(buf); SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE); ft.Throw(VSSDBG_STSWRITER, VSS_E_WRITERERROR_NONRETRYABLE, L"site can't be restored"); }
// indicate a general failure that causes the PreRestore of a component
// to fail
void CSTSWriter::SetPreRestoreFailure(IVssComponent *pComponent, HRESULT hr) { CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSWriter::SetPreRestoreFailure");
// if error is set to NONRETRYABLE then we have already set the
// prerestore failure message and are done
if (ft.hr != VSS_E_WRITERERROR_NONRETRYABLE) return;
CComBSTR bstr; ft.hr = pComponent->GetPreRestoreFailureMsg(&bstr); if (!bstr) { WCHAR buf[256]; swprintf(buf, L"PreRestore failed with error. hr = 0x%08lx", hr); ft.hr = pComponent->SetPreRestoreFailureMsg(buf); }
SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE); }
const DWORD x_cFormats = 8; static const COMPUTER_NAME_FORMAT s_rgFormats[x_cFormats] = { ComputerNameNetBIOS, ComputerNameDnsHostname, ComputerNameDnsDomain, ComputerNameDnsFullyQualified, ComputerNamePhysicalNetBIOS, ComputerNamePhysicalDnsHostname, ComputerNamePhysicalDnsDomain, ComputerNamePhysicalDnsFullyQualified };
// determine if a SQL Server is on the local machine
bool CSTSWriter::ValidateServerIsLocal(LPCWSTR wszServer) { CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSWriter::ValidateServerIsLocal");
if (_wcsicmp(wszServer, L"local") == 0 || _wcsicmp(wszServer, L"(local)") == 0) return true;
LPWSTR wsz = new WCHAR[MAX_COMPUTERNAME_LENGTH]; if (wsz == NULL) ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
DWORD cwc = MAX_COMPUTERNAME_LENGTH;
for(DWORD iFormat = 0; iFormat < x_cFormats; iFormat++) { if (!GetComputerNameEx(s_rgFormats[iFormat], wsz, &cwc)) { if (GetLastError() != ERROR_MORE_DATA) continue;
delete wsz; wsz = new WCHAR[cwc + 1]; if (wsz == NULL) ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
if (!GetComputerNameEx(s_rgFormats[iFormat], wsz, &cwc)) continue; }
if (_wcsicmp(wsz, wszServer) == 0) { delete wsz; return true; } }
delete wsz; return false; }
// determine whether a path is on the local machine or not
bool CSTSWriter::ValidatePathIsLocal(LPCWSTR wszPath) { CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSWriter::ValidatePathIsLocal");
// get full path from supplied path
ULONG ulMountpointBufferLength = GetFullPathName (wszPath, 0, NULL, NULL);
LPWSTR pwszMountPointName = new WCHAR[ulMountpointBufferLength * sizeof (WCHAR)];
if (pwszMountPointName == NULL) ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
BOOL fSuccess = FALSE; if (GetVolumePathName(wszPath, pwszMountPointName, ulMountpointBufferLength)) { WCHAR wszVolumeName[MAX_PATH]; fSuccess = GetVolumeNameForVolumeMountPoint(pwszMountPointName, wszVolumeName, sizeof (wszVolumeName) / sizeof (WCHAR)); }
delete pwszMountPointName; return fSuccess ? true : false; }
|