Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

756 lines
23 KiB

/*++
Copyright (c) 2001 Microsoft Corporation
Abstract:
@doc
@module stssites.cxx | Implementation of CSTSSites
@end
Author:
Brian Berkowitz [brianb] 10/15/2001
Revision History:
Name Date Comments
brianb 10/15/2001 Created
--*/
#include "stdafx.hxx"
#include "vs_inc.hxx"
#include "vs_reg.hxx"
#include "iadmw.h"
#include "iiscnfg.h"
#include "mdmsg.h"
#include "stssites.hxx"
#include "vswriter.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 "STSSITEC"
//
////////////////////////////////////////////////////////////////////////
// toplevel key for enumeration of sites and their DSNs
static LPCWSTR x_STSSECUREKEY = L"Software\\Microsoft\\Shared Tools\\Web Server Extensions\\Secure";
// bottom level keys for sharepoint sites
static LPCWSTR x_STSRegistryKey = L"/LM/W3SVC/";
static LPCWSTR x_STSRegistryKeyFormat = L"/LM/W3SVC/%d:";
static LPCWSTR x_STSMetabaseKey = L"/LM/W3SVC";
static LPCWSTR x_STSMetabaseKeyFormat= L"/LM/W3SVC/%d";
// DSN value
static LPCWSTR x_ValueDSN = L"DSN";
// version key for Sharepoint Team Services 5.0"
static LPCWSTR x_STSVERSIONKEY = L"Software\\Microsoft\\Shared Tools\\Web Server Extensions\\5.0";
// key to Shell Folders properties. Used to get Applications Data directory"
static LPCWSTR x_ShellFoldersKey = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";
// value of applications data directory under Shell folders key
static LPCWSTR x_AppDataValue = L"Common AppData";
// subfolder under Applications data directory for STS data"
static LPCWSTR x_STSSubfolder = L"\\Microsoft\\Web Server Extensions\\50";
// constructor
CSTSSites::CSTSSites() :
m_cSites(0),
m_rgSiteIds(NULL),
m_rootKey(KEY_READ|KEY_ENUMERATE_SUB_KEYS),
m_hQuotaLock(INVALID_HANDLE_VALUE),
m_wszAppDataFolder(NULL)
{
}
// destructor
CSTSSites::~CSTSSites()
{
delete m_rgSiteIds;
UnlockSites();
UnlockQuotaDatabase();
CoTaskMemFree(m_wszAppDataFolder);
}
// initialize the array of site ids. Returns FALSE if there are no sites
bool CSTSSites::Initialize()
{
CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSSites::Initialize");
if (!m_rootKey.Open(HKEY_LOCAL_MACHINE, x_STSSECUREKEY))
return false;
CVssRegistryKeyIterator iter;
iter.Attach(m_rootKey);
try
{
m_cSites = iter.GetSubkeysCount();
m_rgSiteIds = new DWORD[m_cSites];
if (m_rgSiteIds == NULL)
ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"can't allocate site id array");
for(UINT iSite = 0; iSite < m_cSites; iSite++)
{
DWORD siteId;
BS_ASSERT(!iter.IsEOF());
LPCWSTR wszSiteName = iter.GetCurrentKeyName();
BS_ASSERT(wcslen(wszSiteName) > wcslen(x_STSRegistryKey));
BS_ASSERT(wcsncmp(wszSiteName, x_STSRegistryKey, wcslen(x_STSRegistryKey)) == 0);
#ifdef DEBUG
DWORD cFields =
#endif
swscanf(wszSiteName, x_STSRegistryKeyFormat, &siteId);
BS_ASSERT(cFields == 1);
m_rgSiteIds[iSite] = siteId;
iter.MoveNext();
}
}
catch(...)
{
iter.Detach();
throw;
}
iter.Detach();
return true;
}
// return the id of a specific site
VSS_PWSZ CSTSSites::GetSiteDSN(DWORD iSite)
{
CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSSites::GetSiteDSN");
CVssRegistryKey key(KEY_READ);
BS_ASSERT(iSite < m_cSites);
DWORD siteId = m_rgSiteIds[iSite];
WCHAR buf[MAX_PATH];
swprintf(buf, x_STSRegistryKeyFormat, siteId);
if (!key.Open(m_rootKey.GetHandle(), buf))
ft.Throw(VSSDBG_STSWRITER, E_UNEXPECTED, L"missing registry key");
VSS_PWSZ pwszDSN = NULL;
key.GetValue(x_ValueDSN, pwszDSN);
BS_ASSERT(pwszDSN);
return pwszDSN;
}
// determine if this is the correct sharepoint version
bool CSTSSites::ValidateSharepointVersion()
{
CVssRegistryKey key;
return key.Open(HKEY_LOCAL_MACHINE, x_STSVERSIONKEY);
}
void CSTSSites::SetupMetabaseInterface()
{
CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSSites::SetupMetabaseInterface");
if (!m_pMetabase)
{
ft.hr = CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, (void **) &m_pMetabase);
ft.CheckForError(VSSDBG_STSWRITER, L"CoCreateInstance MSAdminBase");
}
}
// return pointer to site content root. The return value should be
// freed using CoTaskMemFree by the caller
VSS_PWSZ CSTSSites::GetSiteRoot(DWORD iSite)
{
CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSSites::GetSiteRoles");
METADATA_HANDLE h;
static const DWORD x_MDTimeout = 2000;
BS_ASSERT(iSite < m_cSites);
DWORD siteId = m_rgSiteIds[iSite];
WCHAR buf[METADATA_MAX_NAME_LEN];
SetupMetabaseInterface();
swprintf(buf, x_STSMetabaseKeyFormat, siteId);
ft.hr = m_pMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, buf, METADATA_PERMISSION_READ, x_MDTimeout, &h);
ft.CheckForError(VSSDBG_STSWRITER, L"IMSAdminBase::OpenKey");
CVssAutoMetabaseHandle MetaHandle(m_pMetabase, h);
METADATA_RECORD rec;
DWORD dwBufLen = METADATA_MAX_NAME_LEN;
PBYTE pbBuffer = (BYTE *) CoTaskMemAlloc(dwBufLen);
if (pbBuffer == NULL)
ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
rec.dwMDAttributes = METADATA_INHERIT;
rec.dwMDUserType = IIS_MD_UT_SERVER,
rec.dwMDDataType = ALL_METADATA;
rec.dwMDDataLen = dwBufLen;
rec.pbMDData = pbBuffer;
rec.dwMDIdentifier = MD_VR_PATH;
DWORD dwReqSize;
ft.hr = m_pMetabase->GetData(h, L"/root", &rec, &dwReqSize);
if (ft.hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
{
CoTaskMemFree(pbBuffer);
pbBuffer = (BYTE *) CoTaskMemAlloc(dwReqSize);
if (pbBuffer == NULL)
ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
rec.dwMDDataLen = dwReqSize;
rec.pbMDData = pbBuffer;
ft.hr = m_pMetabase->GetData(h, L"/root", &rec, &dwReqSize);
}
ft.CheckForError(VSSDBG_STSWRITER, L"IMSAdminBase::GetData");
return (WCHAR *) pbBuffer;
}
void CSTSSites::LockSiteContents(DWORD iSite)
{
CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSSites::LockSiteContents");
VSS_PWSZ wszContentRoot = GetSiteRoot(iSite);
WCHAR *wszCurrentFile = NULL;
char *szFile = NULL;
WCHAR *wszFile = NULL;
WCHAR *wszNewRoot = NULL;
CSimpleArray<VSS_PWSZ> rgwszRoots;
try
{
wszCurrentFile = new WCHAR[wcslen(wszContentRoot) + 1];
if (wszCurrentFile == NULL)
ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
wcscpy(wszCurrentFile, wszContentRoot);
rgwszRoots.Add(wszCurrentFile);
wszCurrentFile = NULL;
DWORD iCurrentPos = 0;
DWORD iEndLevel = 1;
CoTaskMemFree(wszContentRoot);
wszContentRoot = NULL;
while(iCurrentPos < iEndLevel)
{
for(; iCurrentPos < iEndLevel; iCurrentPos++)
{
LPCWSTR wszCurrentRoot = rgwszRoots[iCurrentPos];
wszCurrentFile = new WCHAR[wcslen(wszCurrentRoot) + MAX_PATH + 2];
if (wszCurrentFile == NULL)
ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
// get front page lock
wcscpy(wszCurrentFile, wszCurrentRoot);
wcscat(wszCurrentFile, L"\\_vti_pvt\\frontpg.lck");
TryLock(wszCurrentFile, false);
// get service lock
wcscpy(wszCurrentFile, wszCurrentRoot);
wcscat(wszCurrentFile, L"\\_vti_pvt\\service.lck");
TryLock(wszCurrentFile, false);
// find child sub webs
wcscpy(wszCurrentFile, wszCurrentRoot);
wcscat(wszCurrentFile, L"\\_vti_pvt\\services.cnf");
CVssAutoWin32Handle h = CreateFile
(
wszCurrentFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL
);
if (h == INVALID_HANDLE_VALUE)
{
DWORD dwErr = GetLastError();
if (dwErr == ERROR_PATH_NOT_FOUND ||
dwErr == ERROR_FILE_NOT_FOUND)
continue;
ft.TranslateGenericError
(
VSSDBG_STSWRITER,
HRESULT_FROM_WIN32(GetLastError()),
L"CreateFile(%s)",
wszCurrentFile
);
}
DWORD dwSize = GetFileSize(h, NULL);
if (dwSize == 0)
ft.TranslateGenericError
(
VSSDBG_STSWRITER,
HRESULT_FROM_WIN32(GetLastError()),
L"GetFileSize(%s)",
wszCurrentFile
);
szFile = new char[dwSize + 1];
wszFile = new WCHAR[dwSize + 1];
if (szFile == NULL || wszFile == NULL)
ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
DWORD dwRead;
if (!ReadFile(h, szFile, dwSize, &dwRead, NULL))
ft.TranslateGenericError
(
VSSDBG_STSWRITER,
HRESULT_FROM_WIN32(GetLastError()),
L"ReadFile(%s)",
wszCurrentFile
);
szFile[dwSize] = '\0';
if (!MultiByteToWideChar
(
CP_ACP,
MB_ERR_INVALID_CHARS,
szFile,
dwSize,
wszFile,
dwSize))
{
ft.hr = HRESULT_FROM_WIN32(GetLastError());
ft.CheckForError(VSSDBG_STSWRITER, L"MultiByteToWideChar");
}
WCHAR *pwcCur = wszFile;
WCHAR *pwcMax = wszFile + dwSize;
while(pwcCur < pwcMax)
{
WCHAR *pwcEnd = wcschr(pwcCur, L'\n');
if (pwcEnd == NULL)
pwcEnd = pwcMax;
*pwcEnd = L'\0';
stripWhiteChars(pwcCur);
if (*pwcCur == L'\0' || *pwcCur != L'/' || pwcCur[1] == L'\0')
{
pwcCur = pwcEnd + 1;
continue;
}
wszNewRoot = new WCHAR[wcslen(pwcCur) + wcslen(wszCurrentRoot) + 1];
if (wszNewRoot == NULL)
ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
wcscpy(wszNewRoot, wszCurrentRoot);
// use backslash instead of forward slash
wcscat(wszNewRoot, L"\\");
// root of subweb
wcscat(wszNewRoot, pwcCur+1);
rgwszRoots.Add(wszNewRoot);
wszNewRoot = NULL;
pwcCur = pwcEnd + 1;
}
delete [] wszFile;
wszFile = NULL;
delete [] szFile;
szFile = NULL;
}
iCurrentPos = iEndLevel;
iEndLevel = rgwszRoots.GetSize();
}
}
catch(...)
{
UnlockSites();
delete [] wszNewRoot;
delete [] wszFile;
delete [] szFile;
delete wszCurrentFile;
CoTaskMemFree(wszContentRoot);
for (int x = 0; x < rgwszRoots.GetSize(); x++)
delete [] rgwszRoots[x];
throw;
}
for (int x = 0; x < rgwszRoots.GetSize(); x++)
delete [] rgwszRoots[x];
}
// remove white characters from beginning and ending of the string
void CSTSSites::stripWhiteChars(LPWSTR &wsz)
{
static LPCWSTR x_wszWhiteChars = L"^[ \t]+";
while(*wsz != L'\0')
{
if (wcschr(x_wszWhiteChars, *wsz) == NULL)
break;
wsz++;
}
if (*wsz == L'\0')
return;
LPWSTR wszEnd = wsz + wcslen(wsz) - 1;
while(wszEnd > wsz)
{
if (wcschr(x_wszWhiteChars, *wszEnd) == NULL && *wszEnd != L'\r')
break;
*wszEnd = L'\0';
wszEnd--;
}
}
void CSTSSites::TryLock(LPCWSTR wszFile, bool bQuotaFile)
{
static const DWORD x_MAX_RETRIES = 60;
static const DWORD x_SLEEP_INTERVAL = 1000;
HANDLE h = INVALID_HANDLE_VALUE;
for(DWORD i = 0; i < x_MAX_RETRIES; i++)
{
h = CreateFile
(
wszFile,
GENERIC_READ|GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL
);
if (h != INVALID_HANDLE_VALUE)
break;
DWORD dwErr = GetLastError();
if (dwErr == ERROR_SHARING_VIOLATION)
{
Sleep(x_SLEEP_INTERVAL);
continue;
}
// assume file doesn't exist
return;
}
if (i >= x_MAX_RETRIES)
throw VSS_E_WRITERERROR_TIMEOUT;
BS_ASSERT(h != INVALID_HANDLE_VALUE);
try
{
if (bQuotaFile)
{
BS_ASSERT(m_hQuotaLock == INVALID_HANDLE_VALUE);
m_hQuotaLock = h;
}
else
m_rgContentLocks.Add(h);
}
catch(...)
{
// add failed, close handle and rethrow error
CloseHandle(h);
throw;
}
}
void CSTSSites::UnlockSites()
{
DWORD dwSize = m_rgContentLocks.GetSize();
for(DWORD i = 0; i < dwSize; i++)
CloseHandle(m_rgContentLocks[i]);
m_rgContentLocks.RemoveAll();
}
// lock the quota database
void CSTSSites::LockQuotaDatabase()
{
CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSSites::LockQuotaDatabase");
// do nothing if quota database is already locked
if (m_hQuotaLock != INVALID_HANDLE_VALUE)
return;
static LPCWSTR x_wszLockFile = L"\\owsuser.lck";
VSS_PWSZ wszDbRoot = GetQuotaDatabase();
LPWSTR wsz = NULL;
try
{
wsz = new WCHAR[wcslen(wszDbRoot) + 1 + wcslen(x_wszLockFile)];
if (wsz == NULL)
ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
wcscpy(wsz, wszDbRoot);
wcscat(wsz, x_wszLockFile);
TryLock(wsz, true);
delete wsz;
CoTaskMemFree(wszDbRoot);
}
catch(...)
{
delete wsz;
CoTaskMemFree(wszDbRoot);
throw;
}
}
// unlock the quota database
void CSTSSites::UnlockQuotaDatabase()
{
if (m_hQuotaLock != INVALID_HANDLE_VALUE)
{
CloseHandle(m_hQuotaLock);
m_hQuotaLock = INVALID_HANDLE_VALUE;
}
}
// get location of Documents And Settings/All Users folder
LPCWSTR CSTSSites::GetAppDataFolder()
{
CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSSites::GetAppDataFolder");
if (m_wszAppDataFolder)
return m_wszAppDataFolder;
CVssRegistryKey key;
if (!key.Open(HKEY_LOCAL_MACHINE, x_ShellFoldersKey))
ft.Throw(VSSDBG_STSWRITER, E_UNEXPECTED, L"shell folders key is missing");
key.GetValue(x_AppDataValue, m_wszAppDataFolder);
return m_wszAppDataFolder;
}
// get location of directory containing the quota database for
// sharepoint. Caller should call CoTaskMemFree on the returned value
VSS_PWSZ CSTSSites::GetQuotaDatabase()
{
CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSSites::GetQuotaDatabase");
LPCWSTR wszAppData = GetAppDataFolder();
DWORD cwc = (DWORD) (wcslen(wszAppData) + wcslen(x_STSSubfolder) + 1);
VSS_PWSZ wsz = (VSS_PWSZ) CoTaskMemAlloc(cwc * sizeof(WCHAR));
if (wsz == NULL)
ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
wcscpy(wsz, wszAppData);
wcscat(wsz, x_STSSubfolder);
return wsz;
}
// return of the root directory for the sites roles database under
// the app data folder
VSS_PWSZ CSTSSites::GetSiteRoles(DWORD iSite)
{
CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSSites::GetSiteRoles");
DWORD siteId = GetSiteId(iSite);
WCHAR buf[32];
swprintf(buf, L"\\W3SVC%d", siteId);
LPCWSTR wszAppData = GetAppDataFolder();
DWORD cwc = (DWORD) (wcslen(wszAppData) + wcslen(x_STSSubfolder) + wcslen(buf) + 1);
VSS_PWSZ wsz = (VSS_PWSZ) CoTaskMemAlloc(cwc * sizeof(WCHAR));
if (wsz == NULL)
ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
wcscpy(wsz, wszAppData);
wcscat(wsz, x_STSSubfolder);
wcscat(wsz, buf);
return wsz;
}
VSS_PWSZ CSTSSites::GetSiteBasicInfo(DWORD iSite, DWORD propId)
{
CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSSites::GetSiteBasicInfo");
METADATA_HANDLE h;
static const DWORD x_MDTimeout = 2000;
BS_ASSERT(iSite < m_cSites);
DWORD siteId = m_rgSiteIds[iSite];
SetupMetabaseInterface();
ft.hr = m_pMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, x_STSMetabaseKey, METADATA_PERMISSION_READ, x_MDTimeout, &h);
ft.CheckForError(VSSDBG_STSWRITER, L"IMSAdminBase::OpenKey");
CVssAutoMetabaseHandle MetaHandle(m_pMetabase, h);
METADATA_RECORD rec;
DWORD dwBufLen = METADATA_MAX_NAME_LEN;
PBYTE pbBuffer = (BYTE *) CoTaskMemAlloc(dwBufLen);
if (pbBuffer == NULL)
ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
rec.dwMDAttributes = METADATA_INHERIT;
rec.dwMDUserType = IIS_MD_UT_SERVER,
rec.dwMDDataType = ALL_METADATA;
rec.dwMDDataLen = dwBufLen;
rec.pbMDData = pbBuffer;
rec.dwMDIdentifier = propId;
WCHAR buf[16];
swprintf(buf, L"/%d", siteId);
DWORD dwReqSize;
ft.hr = m_pMetabase->GetData(h, buf, &rec, &dwReqSize);
if (ft.hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
{
CoTaskMemFree(pbBuffer);
pbBuffer = (BYTE *) CoTaskMemAlloc(dwReqSize);
if (pbBuffer == NULL)
ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
rec.dwMDDataLen = dwReqSize;
rec.pbMDData = pbBuffer;
ft.hr = m_pMetabase->GetData(h, buf, &rec, &dwReqSize);
}
if (ft.hr == MD_ERROR_DATA_NOT_FOUND)
return NULL;
ft.CheckForError(VSSDBG_STSWRITER, L"IMSAdminBase::GetData");
return (WCHAR *) pbBuffer;
}
// return comments for site (site description). Caller is responsible
// for freeing up the memory using CoTaskMemFree
VSS_PWSZ CSTSSites::GetSiteComment(DWORD iSite)
{
return GetSiteBasicInfo(iSite, MD_SERVER_COMMENT);
}
// return ip address of the site if it exists. Caller is responsible for
// freeing up the memory using CoTaskMemFree
VSS_PWSZ CSTSSites::GetSiteIpAddress(DWORD iSite)
{
CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSSites::GetSiteIpAddress");
VSS_PWSZ wszBindings = GetSiteBasicInfo(iSite, MD_SERVER_BINDINGS);
if (wszBindings == NULL)
return NULL;
LPWSTR wszHost = wcsrchr(wszBindings, L':');
if (wszHost == NULL)
{
CoTaskMemFree(wszBindings);
return NULL;
}
*wszHost = '\0';
LPCWSTR wszPort = wcsrchr(wszBindings, L':');
if (wszPort == NULL || wszPort == wszBindings)
{
CoTaskMemFree(wszBindings);
return NULL;
}
DWORD cwc = (DWORD) (wszPort - wszBindings);
VSS_PWSZ pwszRet = (VSS_PWSZ) CoTaskMemAlloc(cwc * sizeof(WCHAR));
if (pwszRet == NULL)
{
CoTaskMemFree(wszBindings);
ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
}
wcsncpy(pwszRet, wszBindings, cwc - 1);
pwszRet[cwc - 1] = L'\0';
return pwszRet;
}
// return port address of the site if it exists. Caller is responsible for
// freeing up the memory using CoTaskMemFree
DWORD CSTSSites::GetSitePort(DWORD iSite)
{
CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSSites::GetSiteIpAddress");
VSS_PWSZ wszBindings = GetSiteBasicInfo(iSite, MD_SERVER_BINDINGS);
if (wszBindings == NULL)
return NULL;
LPWSTR wszHost = wcsrchr(wszBindings, L':');
if (wszHost == NULL)
{
CoTaskMemFree(wszBindings);
return NULL;
}
*wszHost = L'\0';
LPWSTR wszPort = wcsrchr(wszBindings, L':');
if (wszPort == NULL || wszPort + 1 == wszHost)
{
CoTaskMemFree(wszBindings);
return 0;
}
DWORD dwPort = _wtoi(wszPort + 1);
CoTaskMemFree(wszBindings);
return dwPort;
}
// return port address of the site if it exists. Caller is responsible for
// freeing up the memory using CoTaskMemFree
VSS_PWSZ CSTSSites::GetSiteHost(DWORD iSite)
{
CVssFunctionTracer ft(VSSDBG_STSWRITER, L"CSTSSites::GetSiteIpAddress");
VSS_PWSZ wszBindings = GetSiteBasicInfo(iSite, MD_SERVER_BINDINGS);
if (wszBindings == NULL)
return NULL;
LPCWSTR wszHost = wcsrchr(wszBindings, L':');
if (wszHost == NULL || wcslen(wszHost) == 1)
{
CoTaskMemFree(wszBindings);
return NULL;
}
VSS_PWSZ pwszRet = (VSS_PWSZ) CoTaskMemAlloc(wcslen(wszHost));
if (pwszRet == NULL)
{
CoTaskMemFree(wszBindings);
ft.Throw(VSSDBG_STSWRITER, E_OUTOFMEMORY, L"out of memory");
}
wcscpy(pwszRet, wszHost + 1);
CoTaskMemFree(wszBindings);
return pwszRet;
}