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.
 
 
 
 
 
 

636 lines
15 KiB

//+----------------------------------------------------------------------------
//
// File: PbkCache.cpp
//
// Module: Common pbk parser
//
// Synopsis: Caches parsed pbk files to improve performance. Through
// XP, we would re-load and re-parse the phonebook file
// every time a RAS API is called. Really, we need to
// reload the file only when the file on disk changes or when
// a new device is introduced to the system.
//
// Copyright (c) 2000-2001 Microsoft Corporation
//
// Author: 11/03/01 Paul Mayfield
//
//+----------------------------------------------------------------------------
#ifdef _PBK_CACHE_
extern "C"
{
#include <windows.h> // Win32 core
#include <pbkp.h>
#include <nouiutil.h>
#include <dtl.h>
}
#define PBK_CACHE_MAX_RASFILES 500 // Should match MAX_RASFILES
#define PBK_CACHE_INVALID_SLOT (PBK_CACHE_MAX_RASFILES + 1)
//+----------------------------------------------------------------------------
//
// Synopsis: A node in the pbk cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
class PbkCacheNode
{
public:
PbkCacheNode();
~PbkCacheNode();
VOID Close();
DWORD SetFileName(IN WCHAR* pszFileName);
WCHAR* GetPath() {return m_pbFile.pszPath;}
FILETIME GetReadTime() {return m_ftRead;}
DWORD GetLastWriteTime(FILETIME* pTime);
DWORD Reload();
DTLLIST* GetEntryList() {return m_pbFile.pdtllistEntries;}
private:
PBFILE m_pbFile;
FILETIME m_ftRead;
PWCHAR m_pszFileName;
};
//+----------------------------------------------------------------------------
//
// Synopsis: The phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
class PbkCache
{
public:
PbkCache();
~PbkCache();
DWORD Initialize();
DWORD
GetEntry(
IN WCHAR* pszPhonebook,
IN WCHAR* pszEntry,
OUT DTLNODE** ppEntryNode);
VOID
Lock() {EnterCriticalSection(&m_csLock);}
VOID
Unlock() {LeaveCriticalSection(&m_csLock);}
private:
PbkCacheNode* m_Files[PBK_CACHE_MAX_RASFILES];
CRITICAL_SECTION m_csLock;
DWORD
InsertNewNode(
IN PWCHAR pszPhonebook,
IN DWORD dwSlot,
OUT PbkCacheNode** ppNode);
VOID
FindFile(
IN WCHAR* pszFileName,
OUT PbkCacheNode** ppNode,
OUT DWORD* pdwIndex);
};
static PbkCache* g_pPbkCache = NULL;
//+----------------------------------------------------------------------------
//
// Synopsis: Instantiates the phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
PbkCacheNode::PbkCacheNode() : m_pszFileName(NULL)
{
ZeroMemory(&m_pbFile, sizeof(m_pbFile));
ZeroMemory(&m_ftRead, sizeof(m_ftRead));
m_pbFile.hrasfile = -1;
}
//+----------------------------------------------------------------------------
//
// Synopsis: Instantiates the phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
PbkCacheNode::~PbkCacheNode()
{
Close();
SetFileName(NULL);
}
//+----------------------------------------------------------------------------
//
// Synopsis: Closes the file referred to by this cache node
//
// Created: pmay
//
//-----------------------------------------------------------------------------
VOID
PbkCacheNode::Close()
{
if (m_pbFile.hrasfile != -1)
{
ClosePhonebookFile(&m_pbFile);
}
ZeroMemory(&m_pbFile, sizeof(m_pbFile));
m_pbFile.hrasfile = -1;
ZeroMemory(&m_ftRead, sizeof(m_ftRead));
}
//+----------------------------------------------------------------------------
//
// Synopsis: Sets the file name for this node
//
// Created: pmay
//
//-----------------------------------------------------------------------------
DWORD
PbkCacheNode::SetFileName(
IN WCHAR* pszFileName)
{
Free0(m_pszFileName);
m_pszFileName = NULL;
// Copy the file name
//
if (pszFileName)
{
m_pszFileName = StrDup( pszFileName );
if (m_pszFileName == NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
}
return NO_ERROR;
}
//+----------------------------------------------------------------------------
//
// Synopsis: Instantiates the phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
DWORD
PbkCacheNode::GetLastWriteTime(
OUT FILETIME* pTime)
{
BOOL fOk;
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD dwErr = NO_ERROR;
//For whistler bug 537369 gangz
//We cannot leave the handle open for ever, have to close it after using it.
// so delete the m_hFile data member
// Rather, re-open it and get its information by handle
if (m_pszFileName == NULL || TEXT('\0') == m_pszFileName[0] )
{
return ERROR_CAN_NOT_COMPLETE;
}
if( NULL == pTime )
{
return ERROR_INVALID_PARAMETER;
}
dwErr = GetFileLastWriteTime( m_pszFileName, pTime );
return dwErr;
}
//+----------------------------------------------------------------------------
//
// Synopsis: Instantiates the phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
DWORD
PbkCacheNode::Reload()
{
DWORD dwErr = NO_ERROR;
if (m_pszFileName == NULL)
{
return ERROR_CAN_NOT_COMPLETE;
}
do
{
Close();
// Load the RasFile
//
dwErr = ReadPhonebookFileEx(
m_pszFileName,
NULL,
NULL,
RPBF_NoCreate,
&m_pbFile,
&m_ftRead);
if (dwErr != NO_ERROR)
{
break;
}
} while (FALSE);
// Cleanup
//
{
if (dwErr != NO_ERROR)
{
Close();
}
}
return dwErr;
}
//+----------------------------------------------------------------------------
//
// Synopsis: Instantiates the phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
PbkCache::PbkCache()
{
ZeroMemory(m_Files, sizeof(m_Files));
}
//+----------------------------------------------------------------------------
//
// Synopsis: Destroys the phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
PbkCache::~PbkCache()
{
UINT i;
DeleteCriticalSection(&m_csLock);
for (i = 0; i < PBK_CACHE_MAX_RASFILES; i++)
{
if (m_Files[i])
{
delete m_Files[i];
m_Files[i] = NULL;
}
}
}
//+----------------------------------------------------------------------------
//
// Synopsis: Initializes the phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
DWORD
PbkCache::Initialize()
{
DWORD dwErr = NO_ERROR;
__try
{
InitializeCriticalSection(&m_csLock);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwErr = HRESULT_FROM_WIN32(GetExceptionCode());
}
return dwErr;
}
//+----------------------------------------------------------------------------
//
// Synopsis: Initializes the phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
DWORD
PbkCache::GetEntry(
IN WCHAR* pszPhonebook,
IN WCHAR* pszEntry,
OUT DTLNODE** ppEntryNode)
{
DWORD dwErr, dwRet, dwSlot = PBK_CACHE_INVALID_SLOT;
PbkCacheNode* pCacheNode = NULL;
DTLNODE* pEntryNode, *pCopyNode = NULL;
PBENTRY* pEntry;
FILETIME ftWrite, ftRead;
BOOL fFound = FALSE;
TRACE2("PbkCache::GetEntry %S %S", pszPhonebook, pszEntry);
Lock();
do
{
FindFile(pszPhonebook, &pCacheNode, &dwSlot);
// The file is not in the cache. Insert it.
//
if (pCacheNode == NULL)
{
TRACE1("Inserting new pbk cache node %d", dwSlot);
dwErr = InsertNewNode(pszPhonebook, dwSlot, &pCacheNode);
if (dwErr != NO_ERROR)
{
break;
}
}
// The file is in the cache. Reload it if needed
//
else
{
ftRead = pCacheNode->GetReadTime();
dwErr = pCacheNode->GetLastWriteTime(&ftWrite);
if (dwErr != NO_ERROR)
{
break;
}
if (CompareFileTime(&ftRead, &ftWrite) < 0)
{
TRACE2("Reloading pbk cache %d (%S)", dwSlot, pszPhonebook);
dwErr = pCacheNode->Reload();
if (dwErr != NO_ERROR)
{
break;
}
}
}
// Find the entry in question
//
dwErr = ERROR_CANNOT_FIND_PHONEBOOK_ENTRY;
for (pEntryNode = DtlGetFirstNode( pCacheNode->GetEntryList() );
pEntryNode;
pEntryNode = DtlGetNextNode( pEntryNode ))
{
pEntry = (PBENTRY*) DtlGetData(pEntryNode);
if (lstrcmpi(pEntry->pszEntryName, pszEntry) == 0)
{
fFound = TRUE;
dwErr = NO_ERROR;
pCopyNode = DuplicateEntryNode(pEntryNode);
if (pCopyNode == NULL)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
}
break;
}
}
} while (FALSE);
Unlock();
// Prepare the return value
//
if (pCopyNode)
{
*ppEntryNode = pCopyNode;
dwRet = NO_ERROR;
}
else if (dwErr == ERROR_CANNOT_FIND_PHONEBOOK_ENTRY)
{
dwRet = dwErr;
}
else
{
dwRet = ERROR_CANNOT_OPEN_PHONEBOOK;
}
TRACE3(
"PbkCache::GetEntry returning 0x%x 0x%x fFound=%d",
dwErr,
dwRet,
fFound);
return dwRet;
}
//+----------------------------------------------------------------------------
//
// Synopsis: Searches for a phonebook file in the cache. If the file is not
// in the cache, then the index in which to insert that file is
// returned.
//
// Return values:
// If file is found, *ppNode has node and *pdwIndex has the index
// If file not found, *ppNode == NULL. *pdwIndex has insert point
// If cache is full and file not found:
// *ppNode == NULL,
// *pdwIndex == PBK_CACHE_INVALID_SLOT
// Created: pmay
//
//-----------------------------------------------------------------------------
VOID
PbkCache::FindFile(
IN WCHAR* pszFileName,
OUT PbkCacheNode** ppNode,
OUT DWORD* pdwIndex)
{
DWORD i;
*pdwIndex = PBK_CACHE_INVALID_SLOT;
for (i = 0; i < PBK_CACHE_MAX_RASFILES; i++)
{
if (m_Files[i])
{
if (lstrcmpi(pszFileName, m_Files[i]->GetPath()) == 0)
{
*ppNode = m_Files[i];
*pdwIndex = i;
break;
}
}
else
{
if (*pdwIndex == PBK_CACHE_INVALID_SLOT)
{
*pdwIndex = i;
}
}
}
}
//+----------------------------------------------------------------------------
//
// Synopsis: Inserts a node in the give slot in the cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
DWORD
PbkCache::InsertNewNode(
IN PWCHAR pszPhonebook,
IN DWORD dwSlot,
OUT PbkCacheNode** ppNode)
{
PbkCacheNode* pCacheNode = NULL;
DWORD dwErr = NO_ERROR;
do
{
if (dwSlot == PBK_CACHE_INVALID_SLOT)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
break;
}
pCacheNode = new PbkCacheNode();
if (pCacheNode == NULL)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
break;
}
dwErr = pCacheNode->SetFileName(pszPhonebook);
if (dwErr != NO_ERROR)
{
break;
}
dwErr = pCacheNode->Reload();
if (dwErr != NO_ERROR)
{
break;
}
m_Files[dwSlot] = pCacheNode;
*ppNode = pCacheNode;
} while (FALSE);
// Cleanup
//
{
if (dwErr != NO_ERROR)
{
if (pCacheNode)
{
delete pCacheNode;
}
}
}
return dwErr;
}
//+----------------------------------------------------------------------------
//
// Synopsis: check if the phonebook cache is initialized
//
// Created: gangz
//
//-----------------------------------------------------------------------------
BOOL
IsPbkCacheInit()
{
return g_pPbkCache ? TRUE : FALSE;
}
//+----------------------------------------------------------------------------
//
// Synopsis: Initializes the phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
DWORD
PbkCacheInit()
{
DWORD dwErr;
ASSERT(g_pPbkCache == NULL);
g_pPbkCache = new PbkCache;
if (g_pPbkCache == NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
dwErr = g_pPbkCache->Initialize();
if (dwErr != NO_ERROR)
{
delete g_pPbkCache;
g_pPbkCache = NULL;
}
return dwErr;
}
//+----------------------------------------------------------------------------
//
// Synopsis: Cleans up the phonebook cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
VOID
PbkCacheCleanup()
{
PbkCache* pCache = g_pPbkCache;
g_pPbkCache = NULL;
if (pCache)
{
delete pCache;
}
}
//+----------------------------------------------------------------------------
//
// Synopsis: Gets an entry from the cache
//
// Created: pmay
//
//-----------------------------------------------------------------------------
DWORD
PbkCacheGetEntry(
IN WCHAR* pszPhonebook,
IN WCHAR* pszEntry,
OUT DTLNODE** ppEntryNode)
{
if (g_pPbkCache)
{
return g_pPbkCache->GetEntry(pszPhonebook, pszEntry, ppEntryNode);
}
return ERROR_CAN_NOT_COMPLETE;
}
#endif //endof #ifdef _PBK_CACHE_