windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/cmp/asp/fileapp.cpp
2020-09-26 16:20:57 +08:00

535 lines
13 KiB
C++

/*-----------------------------------------------------------------------------
Microsoft Denali
Microsoft Confidential
Copyright 1996 Microsoft Corporation. All Rights Reserved.
Component: File/Application map
File: CFileApp.cpp
Owner: cgrant
File/Application mapping implementation
-----------------------------------------------------------------------------*/
#include "denpre.h"
#pragma hdrstop
#include "dbgutil.h"
#include "memchk.h"
CFileApplicationMap g_FileAppMap;
/*===================================================================
CFileApplnList::CFileApplnList
Constructor
Parameters:
None
Returns:
Nothing
===================================================================*/
CFileApplnList::CFileApplnList() :
m_pszFilename(NULL),
m_fInited(FALSE)
{
}
/*===================================================================
CFileApplnList::~CFileApplnList
Destructor
Parameters:
None
Returns:
Nothing
===================================================================*/
CFileApplnList::~CFileApplnList()
{
// We should have no applications in our list
DBG_ASSERT(m_rgpvApplications.Count() == 0);
// Free the string used as the hash key
if (m_pszFilename)
{
delete [] m_pszFilename;
m_pszFilename = NULL;
}
}
/*===================================================================
CFileApplnList::Init
Initialize the file application list by setting the key to file name
Parameters:
pApplication pointer to the applicaiton
Returns:
S_OK if successful
===================================================================*/
HRESULT CFileApplnList::Init(const TCHAR* pszFilename)
{
HRESULT hr = S_OK;
DBG_ASSERT(pszFilename);
// Make a copy of the file name to
// use as the hash key
DWORD cch = _tcslen(pszFilename);
m_pszFilename = new TCHAR[cch+1];
if (!m_pszFilename)
{
return E_OUTOFMEMORY;
}
_tcscpy(m_pszFilename, pszFilename);
if (FAILED(CLinkElem::Init(m_pszFilename, cch*sizeof(TCHAR))))
{
return E_FAIL;
}
m_fInited = TRUE;
return hr;
}
/*===================================================================
CFileApplnList::UnInit
Clean up the application list
Parameters:
pApplication pointer to the applicaiton
Returns:
S_OK if successful
===================================================================*/
HRESULT CFileApplnList::UnInit(void)
{
HRESULT hr = S_OK;
DBG_ASSERT(m_fInited);
while(m_rgpvApplications.Count())
{
CAppln* pAppln = static_cast<CAppln *>(m_rgpvApplications[0]);
DBG_ASSERT(pAppln);
// Remove this appliation from the array
m_rgpvApplications.Remove(pAppln);
// Release the array's refcount on the application
// This may result in the application being deleted
pAppln->Release();
}
m_rgpvApplications.Clear();
m_fInited = FALSE;
return hr;
}
/*===================================================================
CFileApplnList::AddApplication
Add an application pointer to the list of applications
Parameters:
pApplication pointer to the applicaiton
Returns:
S_OK if successful
Comments
The caller should hold a lock on the hash table containing
the element
===================================================================*/
HRESULT CFileApplnList::AddApplication(void *pApplication)
{
DBG_ASSERT(m_fInited);
DBG_ASSERT(pApplication);
HRESULT hr = S_OK;
int index;
// See if the application is alreay in the list
hr = m_rgpvApplications.Find(pApplication, &index);
if (hr == S_FALSE)
{
// Not found, add it.
// We are going to hold a reference to the application
static_cast<CAppln *>(pApplication)->AddRef();
// Add the application to the list
if (FAILED(hr = m_rgpvApplications.Append(pApplication)))
{
// We failed so give back the refcount we took.
static_cast<CAppln *>(pApplication)->Release();
}
}
return hr;
}
/*===================================================================
CFileApplnList::RemoveApplication
Removes an application pointer from the list of applications
Parameters:
pApplication pointer to the applicaiton
Returns:
S_OK if successful
Comments
The caller should hold a lock on the hash table containing
the element
===================================================================*/
HRESULT CFileApplnList::RemoveApplication(void *pApplication)
{
DBG_ASSERT(m_fInited);
DBG_ASSERT(pApplication);
HRESULT hr = S_OK;
int index;
#ifdef DBG_NOTIFICATION
#if UNICODE
DBGPRINTF((DBG_CONTEXT, "Removing Application entry for %S\n", reinterpret_cast<CAppln *>(pApplication)->GetApplnPath()));
#else
DBGPRINTF((DBG_CONTEXT, "Removing Application entry for %s\n", reinterpret_cast<CAppln *>(pApplication)->GetApplnPath()));
#endif
#endif // DBG_NOTIFICATION
// Remove the application from the list
hr = m_rgpvApplications.Remove(pApplication);
// If the count of applications in the list goes
// to 0, remove the element from the hash table
// and delete it
if (m_rgpvApplications.Count() == 0)
{
#ifdef DBG_NOTIFICATION
#if UNICODE
DBGPRINTF((DBG_CONTEXT, "Deleting File/Application entry for %s\n", m_pszFilename));
#else
DBGPRINTF((DBG_CONTEXT, "Deleting File/Application entry for %s\n", m_pszFilename));
#endif
#endif // DBG_NOTIFICATION
g_FileAppMap.RemoveElem(this);
delete this;
}
// If we found the application to remove it
// we need to release a ref count on the application
if (hr == S_OK)
{
static_cast<CAppln *>(pApplication)->Release();
}
return hr;
}
/*===================================================================
CFileApplnList::GetShutdownApplications
Obtain a list of applications to shut down
Parameters:
None
===================================================================*/
VOID CFileApplnList::GetShutdownApplications(CPtrArray *prgpapplnRestartList)
{
DBG_ASSERT(m_fInited);
HRESULT hr = S_OK;
#ifdef DBG_NOTIFICATION
#if UNICODE
DBGPRINTF((DBG_CONTEXT, "[CFileApplnList] Shutting down %d applications depending on %S.\n", m_rgpvApplications.Count(), m_pszFilename));
#else
DBGPRINTF((DBG_CONTEXT, "[CFileApplnList] Shutting down %d applications depending on %s.\n", m_rgpvApplications.Count(), m_pszFilename));
#endif
#endif // DBG_NOTIFICATION
for (int i = m_rgpvApplications.Count() - 1; i >= 0; i--)
{
CAppln* pAppln = static_cast<CAppln *>(m_rgpvApplications[i]);
DBG_ASSERT(pAppln);
// If not already tombstoned, shut the application down.
// When the application is uninited it will remove itself
// from this list
if (!pAppln->FTombstone())
{
pAppln->AddRef();
prgpapplnRestartList->Append(pAppln);
}
}
}
/*===================================================================
CFileApplicationMap::CFileApplicationMap
Constructor
Parameters:
None
Returns:
Nothing
===================================================================*/
CFileApplicationMap::CFileApplicationMap()
: m_fInited(FALSE),
m_fHashTableInited(FALSE),
m_fCriticalSectionInited(FALSE)
{
}
/*===================================================================
CFileApplicationMap::~CFileApplicationMap
Destructor
Parameters:
None
Returns:
Nothing
===================================================================*/
CFileApplicationMap::~CFileApplicationMap()
{
if (m_fInited)
{
UnInit();
}
}
/*===================================================================
CFileApplicationMap::Init
Initialize the hash table and critical section
Parameters:
None
Returns:
S_OK if successful
===================================================================*/
HRESULT CFileApplicationMap::Init()
{
HRESULT hr = S_OK;
Assert(!m_fInited);
hr = CHashTable::Init(NUM_FILEAPP_HASHING_BUCKETS);
if (FAILED(hr))
{
return hr;
}
m_fHashTableInited = TRUE;
// Init critical section
ErrInitCriticalSection(&m_csLock, hr);
if (FAILED(hr))
{
return(hr);
}
m_fCriticalSectionInited = TRUE;
m_fInited = TRUE;
return S_OK;
}
/*===================================================================
CFileApplicationMap::UnInit
Uninitialize the hash table and critical section
Free any applications lists remaining in the hash
table elements
Parameters:
None
Returns:
S_OK if successful
===================================================================*/
HRESULT CFileApplicationMap::UnInit()
{
if (m_fHashTableInited)
{
// Delete any elements remaining in the hash table
CFileApplnList *pNukeElem = static_cast<CFileApplnList *>(Head());
while (pNukeElem != NULL)
{
CFileApplnList *pNext = static_cast<CFileApplnList *>(pNukeElem->m_pNext);
pNukeElem->UnInit();
delete pNukeElem;
pNukeElem = pNext;
}
// Uninit the hash table
CHashTable::UnInit();
m_fHashTableInited = FALSE;
}
if (m_fCriticalSectionInited)
{
DeleteCriticalSection(&m_csLock);
m_fCriticalSectionInited = FALSE;
}
m_fInited = FALSE;
return S_OK;
}
/*===================================================================
CFileApplicationMap::AddFileApplication
Add a file-application pair to the hash table
Parameters:
pszFilename pointer to string containing name of the file
pAppln pointer to the application associated with the file
Returns:
S_OK if successful
===================================================================*/
HRESULT CFileApplicationMap::AddFileApplication(const TCHAR* pszFilename, CAppln* pAppln)
{
// We must have both a file and an application
DBG_ASSERT(pszFilename);
DBG_ASSERT(pAppln);
HRESULT hr = S_OK;
Lock();
#ifdef DBG_NOTIFICATION
#if UNICODE
DBGPRINTF((DBG_CONTEXT, "Adding File/Application entry for %S\n", pszFilename));
#else
DBGPRINTF((DBG_CONTEXT, "Adding File/Application entry for %s\n", pszFilename));
#endif
#endif // DBG_NOTIFICATION
// See if the file already has an entry
CFileApplnList* pFileApplns = static_cast<CFileApplnList *>(CHashTable::FindElem(pszFilename, _tcslen(pszFilename)*sizeof(TCHAR)));
if (pFileApplns == NULL)
{
// Not found, create new CFileApplnList object
pFileApplns = new CFileApplnList;
if (!pFileApplns)
{
hr = E_OUTOFMEMORY;
goto LExit;
}
// Init CFileApplnList object
hr = pFileApplns->Init(pszFilename);
if (FAILED(hr))
{
delete pFileApplns;
goto LExit;
}
// Add FileApplns object to hash table
if (!CHashTable::AddElem(pFileApplns))
{
delete pFileApplns;
hr = E_FAIL;
goto LExit;
}
}
// Add the application to the list associated with this file
hr = pFileApplns->AddApplication(pAppln);
// Keep this file mapping in the application
// The application will remove itself from this list
// when it is uninited.
pAppln->AddFileApplnEntry(pFileApplns);
LExit:
UnLock();
return hr;
}
/*===================================================================
CFileApplicationMap::ShutdownApplications
Shutdown the applications associated with a file
Parameters:
pszFilename pointer to string containing name of the file
Returns:
TRUE if an application was shutdown, FALSE otherwise
===================================================================*/
BOOL CFileApplicationMap::ShutdownApplications(const TCHAR *pszFilename)
{
DBG_ASSERT(pszFilename);
BOOL fResult = TRUE;
Lock();
CFileApplnList* pFileApplns = static_cast<CFileApplnList *>(CHashTable::FindElem(pszFilename, _tcslen(pszFilename)*sizeof(TCHAR)));
if (pFileApplns)
{
// Get a list of applications we need to shutdown
CPtrArray rgpapplnRestartList;
pFileApplns->GetShutdownApplications(&rgpapplnRestartList);
// Now that we have the list of applications we need to shut down
// we can release the lock
UnLock();
for (int i = 0; i < rgpapplnRestartList.Count(); i++)
{
CAppln *pAppln = (CAppln *)rgpapplnRestartList[i];
pAppln->Restart();
pAppln->Release();
}
// Flush the script cache if any applications were restarted
if (rgpapplnRestartList.Count())
g_ScriptManager.FlushAll();
}
else
{
// No applications to shut down, release the lock
UnLock();
fResult = FALSE;
}
return fResult;
}