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.
 
 
 
 
 
 

1980 lines
59 KiB

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name: conmgr.cxx
Abstract:
Manages list of containers (CConList)
Author:
Adriaan Canter (adriaanc) 04-02-97
--*/
#include <wininetp.h>
#include <cache.hxx>
#define FAILSAFE_TIMEOUT (60000)
/*--------------------- Private Functions -----------------------------------*/
/*-----------------------------------------------------------------------------
DWORD CConMgr::Init
----------------------------------------------------------------------------*/
DWORD CConMgr::Init()
{
DWORD dwError = ConfigureCache();
if (dwError==ERROR_SUCCESS)
{
// Get the extensible cache config info.
// These containers are delay-initialized.
dwError = GetExtensibleCacheConfigInfo(TRUE);
}
else
{
INET_ASSERT(FALSE);
}
return dwError;
}
#ifdef CHECKLOCK_PARANOID
void CConMgr::CheckNoLocks(DWORD dwThreadId)
{
URL_CONTAINER *co;
DWORD idx;
LOCK_CACHE();
for (idx = 0; idx < ConList.Size(); idx++)
{
URL_CONTAINER *co;
co = ConList.Get(idx);
if (co)
{
co->CheckNoLocks(dwThreadId);
co->Release(FALSE);
}
}
UNLOCK_CACHE();
}
#endif
/*-----------------------------------------------------------------------------
BOOL CConMgr::WasModified
----------------------------------------------------------------------------*/
BOOL CConMgr::WasModified(BOOL fUpdateMemory)
{
DWORD dwOldCount = _dwModifiedCount;
return dwOldCount != ReadModifiedCount(fUpdateMemory);
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::ReadModifiedCount
----------------------------------------------------------------------------*/
DWORD CConMgr::ReadModifiedCount(BOOL fUpdateMemory)
{
DWORD dwChangeCount;
DWORD *pdwChangeCount = fUpdateMemory ? &_dwModifiedCount : &dwChangeCount;
_coContent->GetHeaderData(CACHE_HEADER_DATA_CONLIST_CHANGE_COUNT,
pdwChangeCount);
return *pdwChangeCount;
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::IncrementModifiedCount
----------------------------------------------------------------------------*/
void CConMgr::IncrementModifiedCount()
{
DWORD dwLocModified;
_coContent->IncrementHeaderData(CACHE_HEADER_DATA_CONLIST_CHANGE_COUNT,
&dwLocModified);
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::InitFixedContainers
----------------------------------------------------------------------------*/
DWORD CConMgr::InitFixedContainers()
{
DWORD idx;
DWORD dwError = ERROR_SUCCESS;
BOOL fInitSucceeded = TRUE;
// Create and init
_hMutexExtensible = OpenMutex(SYNCHRONIZE, FALSE, TEXT("_!MSFTHISTORY!_"));
if (_hMutexExtensible == NULL && (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_INVALID_NAME))
{
SECURITY_ATTRIBUTES* psa = SHGetAllAccessSA();
if (psa)
{
_hMutexExtensible = CreateMutex(psa, FALSE, TEXT("_!MSFTHISTORY!_"));
}
}
if (_hMutexExtensible == NULL)
{
dwError = GetLastError();
fInitSucceeded = FALSE;
goto exit;
}
_dwLastUnmap = GetTickCountWrap();
LOCK_CACHE();
// Containers are configured. Attempt to initialize.
for (idx = CONTENT; idx < ConList.Size(); idx++)
{
URL_CONTAINER *co;
co = ConList.Get(idx);
if (co)
{
dwError = co->Init();
// NOTE - URL_CONTAINER::Init() returns ERROR_ALREADY_EXISTS
// only if the the existing memory mapped file has been opened
// successfully. If the memory mapped file was created, upgraded
// or corrupted (in both cases the mem mapped file will be reinited)
// the return value will be ERROR_SUCCESS.
if(dwError != ERROR_SUCCESS && dwError != ERROR_ALREADY_EXISTS)
{
fInitSucceeded = FALSE;
goto unlock_exit;
}
// Has the container been created, upgrade or corrupted?
if (dwError == ERROR_SUCCESS)
{
if(idx==CONTENT)
{
// Preload the content container.
LoadContent();
}
else if (idx==COOKIE)
{
CCookieLoader cl;
cl.LoadCookies(co);
}
}
co->Release(FALSE);
}
}
// Enable cachevu for CONTENT and HISTORY.
EnableCacheVu(_coContent->GetCachePath(), CONTENT);
EnableCacheVu(_coHistory->GetCachePath(), HISTORY);
unlock_exit:
UNLOCK_CACHE();
exit:
dwError = (fInitSucceeded ? ERROR_SUCCESS : ERROR_INTERNAL_ERROR);
if (!fInitSucceeded && _hMutexExtensible)
{
CloseHandle(_hMutexExtensible);
_hMutexExtensible = NULL;
}
INET_ASSERT(dwError == ERROR_SUCCESS);
return dwError;
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::LoadContent()
----------------------------------------------------------------------------*/
DWORD CConMgr::LoadContent()
{
DWORD cbFile, dwError = ERROR_FILE_NOT_FOUND;
CHAR szPreloadKey[MAX_PATH],
szUrl[MAX_PATH],
szFile[MAX_PATH];
// Preload registry key string.
memcpy(szPreloadKey, OLD_CACHE_KEY, sizeof(OLD_CACHE_KEY) - 1);
szPreloadKey[sizeof(OLD_CACHE_KEY)-1] = '\\';
memcpy(szPreloadKey + sizeof(OLD_CACHE_KEY), "Preload", sizeof("PreLoad"));
// Construct preload registry object.
REGISTRY_OBJ roPreload(HKEY_CURRENT_USER, szPreloadKey);
REGISTRY_OBJ roIE5Preload;
if (roPreload.GetStatus() != ERROR_SUCCESS)
goto exit;
// Get the storage directory (cdf preload) to compare against to determine if we
// need to set EDITED_CACHE_ENTRY or not. We assume any preload entry not in the
// store dir IS and ECE.
DWORD cb;
CHAR szStorePath[MAX_PATH];
// Store dir is hardwired to "%windir%\Web\"
if ((cb = GetWindowsDirectory(szStorePath, MAX_PATH)))
{
AppendSlashIfNecessary(szStorePath, &cb);
memcpy(szStorePath + cb, WEBDIR_STRING, sizeof(WEBDIR_STRING));
cb += sizeof(WEBDIR_STRING) - 1; //cb now equals size of szStorePath.
}
// Enum the registry url/file values and commit them
// to the cache.
while (roPreload.FindNextValue(szUrl, MAX_PATH,
(LPBYTE) szFile, &(cbFile = MAX_PATH)) == ERROR_SUCCESS)
{
// Strip off any file:// off the file path/name.
CHAR* ptr = szFile;
if (!strnicmp(ptr, "file://", sizeof("file://") - 1))
ptr += sizeof("file://") - 1;
AddUrlArg Args;
memset(&Args, 0, sizeof(Args));
Args.pszUrl = szUrl;
Args.pszFilePath = ptr;
// If this is a Store entry, set the type to 0 else ECE
if (!strnicmp(ptr, szStorePath, cb))
Args.dwEntryType = 0;
else
Args.dwEntryType = EDITED_CACHE_ENTRY;
_coContent->AddUrl(&Args);
}
if (roIE5Preload.WorkWith(&roPreload, "IE5Preload")!=ERROR_SUCCESS)
goto exit;
DWORD cbMaxUrl, cbMaxEntry, cbEntry;
LPSTR pszUrl;
URL_FILEMAP_ENTRY *pEntry;
KEY_QUERY_INFO QueryInfo;
if (ERROR_SUCCESS != roIE5Preload.GetKeyInfo(&QueryInfo))
goto exit;
cbMaxUrl = QueryInfo.MaxValueNameLen + 1;
cbMaxEntry = QueryInfo.MaxValueLen + 1;
pszUrl = new CHAR[cbMaxUrl];
pEntry = (URL_FILEMAP_ENTRY*) new CHAR[cbMaxEntry];
if (!(pszUrl && pEntry))
goto exit;
__try
{
while ((dwError = roIE5Preload.FindNextValue(pszUrl, cbMaxUrl,
(LPBYTE) pEntry, &(cbEntry = cbMaxEntry))) == ERROR_SUCCESS)
{
FILETIME ft;
AddUrlArg Args;
memset(&Args, 0, sizeof(Args));
// Url
Args.pszUrl = pEntry->UrlNameOffset ?
(LPSTR) OFFSET_TO_POINTER(pEntry, pEntry->UrlNameOffset) : NULL;
// File path
Args.pszFilePath = pEntry->InternalFileNameOffset ?
(LPSTR) OFFSET_TO_POINTER(pEntry, pEntry->InternalFileNameOffset) : NULL;
// Header info
Args.pbHeaders = pEntry->HeaderInfoOffset ?
(LPSTR) OFFSET_TO_POINTER(pEntry, pEntry->HeaderInfoOffset) : NULL;
Args.cbHeaders = pEntry->HeaderInfoSize;
// Last modified.
Args.qwLastMod = pEntry->LastModifiedTime;
// Expires time.
DosTime2FileTime(pEntry->dostExpireTime, &ft);
Args.qwExpires = FT2LL(ft);
// Post check time.
DosTime2FileTime(pEntry->dostPostCheckTime, &ft);
Args.qwPostCheck = FT2LL(ft);
// File creation time.
DosTime2FileTime(pEntry->dostFileCreationTime, &ft);
Args.ftCreate = ft;
// File extension.
Args.pszFileExt = pEntry->FileExtensionOffset ?
(LPSTR) OFFSET_TO_POINTER(pEntry, pEntry->FileExtensionOffset) : NULL;
// Entry type.
Args.dwEntryType = pEntry->CacheEntryType;
// File size
Args.dwFileSize = pEntry->dwFileSize;
// Add the url.
_coContent->AddUrl(&Args);
}
} // __try
__except(EXCEPTION_EXECUTE_HANDLER)
{
INET_ASSERT(FALSE);
dwError = GetLastError();
}
ENDEXCEPT
dwError = ERROR_SUCCESS;
if (pszUrl)
delete pszUrl;
if (pEntry)
delete pEntry;
exit:
return dwError;
}
/*-----------------------------------------------------------------------------
HANDLE CConMgr::FindFirstContainer
----------------------------------------------------------------------------*/
HANDLE CConMgr::FindFirstContainer(DWORD *pdwModified, LPINTERNET_CACHE_CONTAINER_INFOA lpContainerInfo, LPDWORD lpdwContainerInfoBufferSize, DWORD dwOptions)
{
DWORD dwError = ERROR_SUCCESS;
CONTAINER_FIND_FIRST_HANDLE *pFind;
DWORD dwContainers = 0;
DWORD dwNames = 0;
DWORD dwPrefixes = 0;
DWORD dwLabels = 0;
DWORD dwTitles = 0;
DWORD dwTotal;
HANDLE hFind = NULL;
DWORD dwModified;
GetExtensibleCacheConfigInfo(FALSE);
LOCK_CACHE();
dwModified = *pdwModified;
*pdwModified = _dwModifiedCount;
if ((CACHE_FIND_CONTAINER_RETURN_NOCHANGE & dwOptions) == 0 ||
dwModified != *pdwModified)
{
for (DWORD i = NCONTAINERS; i < ConList.Size(); i++)
{
URL_CONTAINER *co = ConList.Get(i);
if (co)
{
if (co->IsVisible())
{
dwContainers++;
dwNames += strlen(co->GetCacheName()) + 1;
dwPrefixes += strlen(co->GetCachePrefix()) + 1;
dwLabels += strlen(co->GetVolumeLabel()) + 1;
dwTitles += strlen(co->GetVolumeTitle()) + 1;
}
co->Release(TRUE);
}
}
dwTotal = sizeof(CONTAINER_FIND_FIRST_HANDLE)+
dwContainers*(4 * sizeof(LPSTR)) +
(dwNames+dwPrefixes+dwLabels+dwTitles) * sizeof(char);
hFind = HandleMgr.Alloc (dwTotal);
if (hFind)
{
LPSTR ps;
pFind = (CONTAINER_FIND_FIRST_HANDLE*) HandleMgr.Map (hFind);
pFind->dwSignature = SIGNATURE_CONTAINER_FIND;
pFind->dwContainer = 0;
pFind->dwNumContainers = dwContainers;
if (dwContainers)
{
pFind->ppNames = (LPTSTR *) (((LPBYTE) pFind) + sizeof(CONTAINER_FIND_FIRST_HANDLE));
pFind->ppPrefixes = pFind->ppNames + dwContainers;
pFind->ppLabels = pFind->ppPrefixes + dwContainers;
pFind->ppTitles = pFind->ppLabels + dwContainers;
ps = (LPSTR) (((LPBYTE) pFind) +
sizeof(CONTAINER_FIND_FIRST_HANDLE)+
dwContainers*(4 * sizeof(LPSTR)));
dwContainers = 0;
for (DWORD i = NCONTAINERS; i < ConList.Size(); i++)
{
URL_CONTAINER *co = ConList.Get(i);
if (co)
{
if (co->IsVisible())
{
pFind->ppNames[dwContainers] = ps;
strcpy(ps, co->GetCacheName());
ps += strlen(co->GetCacheName()) + 1;
pFind->ppPrefixes[dwContainers] = ps;
strcpy(ps, co->GetCachePrefix());
ps += strlen(co->GetCachePrefix()) + 1;
pFind->ppLabels[dwContainers] = ps;
strcpy(ps, co->GetVolumeLabel());
ps += strlen(co->GetVolumeLabel()) + 1;
pFind->ppTitles[dwContainers] = ps;
strcpy(ps, co->GetVolumeTitle());
ps += strlen(co->GetVolumeTitle()) + 1;
dwContainers++;
}
co->Release(TRUE);
}
}
}
}
else
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
}
}
else
{
dwError = ERROR_WINHTTP_NO_NEW_CONTAINERS;
}
UNLOCK_CACHE();
if (hFind)
{
if (FindNextContainer(hFind, lpContainerInfo, lpdwContainerInfoBufferSize))
dwError = ERROR_SUCCESS;
else
dwError = GetLastError();
}
if( dwError != ERROR_SUCCESS )
{
FreeFindHandle(hFind);
SetLastError(dwError);
return NULL;
}
return hFind;
}
/*-----------------------------------------------------------------------------
BOOL CConMgr::FindNextContainer
----------------------------------------------------------------------------*/
BOOL CConMgr::FindNextContainer(HANDLE hFind, LPINTERNET_CACHE_CONTAINER_INFOA lpContainerInfo, LPDWORD lpdwContainerInfoBufferSize)
{
// BUGBUG - this logic is borrowed from the original cachapia.cxx.
DWORD dwError;
CONTAINER_FIND_FIRST_HANDLE* pFind;
// Map and validate the handle.
LOCK_CACHE();
pFind = (CONTAINER_FIND_FIRST_HANDLE*) HandleMgr.Map (hFind);
UNLOCK_CACHE();
if (!pFind || pFind->dwSignature != SIGNATURE_CONTAINER_FIND ||
!lpContainerInfo ||
*lpdwContainerInfoBufferSize < sizeof(INTERNET_CACHE_CONTAINER_INFOA))
{
dwError = ERROR_INVALID_PARAMETER;
goto exit;
}
// Continue the enumeration.
if (pFind->dwContainer < pFind->dwNumContainers)
{
DWORD cbName = strlen(pFind->ppNames[pFind->dwContainer])+1;
DWORD cbPrefix = strlen(pFind->ppPrefixes[pFind->dwContainer])+1;
DWORD cbLabel = strlen(pFind->ppLabels[pFind->dwContainer])+1;
DWORD cbTitle = strlen(pFind->ppTitles[pFind->dwContainer])+1;
DWORD cbTotal = cbName+cbPrefix+cbLabel+cbTitle+sizeof(INTERNET_CACHE_CONTAINER_INFOA);
if (cbTotal > *lpdwContainerInfoBufferSize)
{
dwError = ERROR_INSUFFICIENT_BUFFER;
}
else
{
lpContainerInfo->lpszName = (LPSTR) (((LPBYTE) lpContainerInfo) +
sizeof(INTERNET_CACHE_CONTAINER_INFOA));
lpContainerInfo->lpszCachePrefix = lpContainerInfo->lpszName + cbName;
lpContainerInfo->lpszVolumeLabel = lpContainerInfo->lpszCachePrefix + cbPrefix;
lpContainerInfo->lpszVolumeTitle = lpContainerInfo->lpszVolumeLabel + cbLabel;
strcpy(lpContainerInfo->lpszName, pFind->ppNames[pFind->dwContainer]);
strcpy(lpContainerInfo->lpszCachePrefix, pFind->ppPrefixes[pFind->dwContainer]);
strcpy(lpContainerInfo->lpszVolumeLabel, pFind->ppLabels[pFind->dwContainer]);
strcpy(lpContainerInfo->lpszVolumeTitle, pFind->ppTitles[pFind->dwContainer]);
lpContainerInfo->dwCacheVersion = URL_CACHE_VERSION_NUM;
pFind->dwContainer++;
dwError = ERROR_SUCCESS;
}
*lpdwContainerInfoBufferSize = cbTotal;
}
else
{
dwError = ERROR_NO_MORE_ITEMS;
}
exit:
if (dwError != ERROR_SUCCESS)
{
SetLastError(dwError);
return FALSE;
}
return TRUE;
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::GetContainerInfo
----------------------------------------------------------------------------*/
DWORD CConMgr::GetContainerInfo(LPSTR szUrl,
LPINTERNET_CACHE_CONTAINER_INFOA pCI,
LPDWORD pcbCI)
{
URL_CONTAINER *co;
DWORD dwError;
// Find the associated container.
DWORD idx;
LOCK_CACHE();
idx = FindIndexFromPrefix(szUrl);
co = ConList.Get(idx);
if (co)
{
DWORD cbName = strlen(co->GetCacheName()) + 1;
DWORD cbPrefix = strlen(co->GetCachePrefix()) + 1;
DWORD cbLabel = strlen(co->GetVolumeLabel()) + 1;
DWORD cbTitle = strlen(co->GetVolumeTitle()) + 1;
DWORD cbReq = cbName + cbPrefix + cbLabel + cbTitle;
if (cbReq > *pcbCI)
{
*pcbCI = cbReq;
dwError = ERROR_INSUFFICIENT_BUFFER;
}
else
{
pCI->lpszName = (LPSTR) (((LPBYTE) pCI) +
sizeof(INTERNET_CACHE_CONTAINER_INFOA));
pCI->lpszCachePrefix = pCI->lpszName + cbName;
pCI->lpszVolumeLabel = pCI->lpszName + cbName + cbPrefix;
pCI->lpszVolumeTitle = pCI->lpszName + cbName + cbPrefix + cbLabel;
memcpy(pCI->lpszName, co->GetCacheName(), cbName);
memcpy(pCI->lpszCachePrefix, co->GetCachePrefix(), cbPrefix);
memcpy(pCI->lpszVolumeLabel, co->GetVolumeLabel(), cbLabel);
memcpy(pCI->lpszVolumeTitle, co->GetVolumeTitle(), cbTitle);
pCI->dwCacheVersion = URL_CACHE_VERSION_NUM;
*pcbCI = cbReq;
dwError = ERROR_SUCCESS;
}
co->Release(TRUE);
}
else
{
dwError = ERROR_WINHTTP_INTERNAL_ERROR;
}
UNLOCK_CACHE();
return dwError;
}
VOID CompressPath(PTSTR pszPath, PTSTR pszScratch);
/*-----------------------------------------------------------------------------
DWORD CConMgr::CreateContainer
----------------------------------------------------------------------------*/
DWORD CConMgr::CreateContainer(LPCSTR Name, LPCSTR CachePrefix, LPCSTR CachePath, DWORD KBCacheLimit, DWORD dwOptions)
{
BOOL fInsertOk = TRUE;
DWORD dwError = ERROR_SUCCESS;
CHAR szVendorKey[MAX_PATH];
CHAR szDefaultPath[MAX_PATH];
CHAR szCachePath[MAX_PATH];
LONGLONG CacheStartUpLimit;
HKEY hKey;
DWORD cbKeyLen;
hKey = (_fProfilesCapable ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE);
REGISTRY_OBJ* pro = NULL;
MUTEX_HOLDER mh;
if (!Name || !*Name)
{
dwError = ERROR_INVALID_PARAMETER;
goto exit;
}
if (!CachePath || !*CachePath)
{
LPSTR p = _coHistory->GetCachePath();
int len = _coHistory->GetCachePathLen();
int clen = lstrlen(Name);
if (len + clen + sizeof(DIR_SEPARATOR_STRING) > sizeof(szDefaultPath))
{
dwError = ERROR_WINHTTP_INTERNAL_ERROR;
goto exit;
}
memcpy(szDefaultPath, p, len);
memcpy(&szDefaultPath[len], Name, clen);
memcpy(&szDefaultPath[len + clen], DIR_SEPARATOR_STRING, sizeof(DIR_SEPARATOR_STRING));
}
else
{
INET_ASSERT((CachePrefix && *CachePrefix));
// For non-history containers, we need to stuff into the appropriate subcontainer
// Assumption: Content cache never falls here.
if (!GenerateStringWithOrdinal(CachePath,
GlobalIdentity,
szDefaultPath,
ARRAY_ELEMENTS(szDefaultPath)))
{
INET_ASSERT(FALSE);
dwError = ERROR_WINHTTP_INTERNAL_ERROR;
goto exit;
}
}
CachePath = szDefaultPath;
if (KBCacheLimit == 0)
{
CacheStartUpLimit = _coHistory->GetCacheStartUpLimit();
KBCacheLimit = (DWORD) (CacheStartUpLimit / 1024);
}
if (!CachePrefix || !*CachePrefix || !CachePath || !*CachePath)
{
dwError = ERROR_INVALID_PARAMETER;
goto exit;
}
pro = CreateExtensiRegObj(hKey);
if (!pro)
{
dwError = ERROR_ACCESS_DENIED;
goto exit;
}
{
REGISTRY_OBJ& roExtensibleCache = *pro;
mh.Grab(_hMutexExtensible, FAILSAFE_TIMEOUT);
// Get the container paths, prefixes (if any) and default limit values.
while (roExtensibleCache.FindNextKey(szVendorKey, MAX_PATH) == ERROR_SUCCESS)
{
REGISTRY_OBJ roVendor(&roExtensibleCache, szVendorKey);
if (roVendor.GetStatus()==ERROR_SUCCESS)
{
// Path.
TCHAR szScratch[MAX_PATH];
cbKeyLen = MAX_PATH;
if (roVendor.GetValue(CACHE_PATH_VALUE,(LPBYTE) szScratch,&cbKeyLen) != ERROR_SUCCESS)
continue;
ExpandEnvironmentStrings(szScratch, szCachePath, sizeof(szCachePath)-1); // don't count the NULL
if (!stricmp(szVendorKey, Name) || !stricmp(CachePath, szCachePath))
{
fInsertOk = FALSE;
break;
}
}
}
if (fInsertOk)
{
REGISTRY_OBJ roNewVendor(&roExtensibleCache, (LPSTR)Name, CREATE_KEY_IF_NOT_EXISTS);
if (roNewVendor.GetStatus() == ERROR_SUCCESS)
{
CHAR szScratch[MAX_PATH];
CompressPath((LPTSTR)CachePath, szScratch);
// Path.
if ((dwError = roNewVendor.SetValue(CACHE_PATH_VALUE, (LPSTR)szScratch, REG_EXPAND_SZ)) != ERROR_SUCCESS)
goto exit;
// Prefix.
if ((dwError = roNewVendor.SetValue(CACHE_PREFIX_VALUE, (LPSTR)CachePrefix, REG_SZ)) != ERROR_SUCCESS)
goto exit;
// Limit.
if ((dwError = roNewVendor.SetValue(CACHE_LIMIT_VALUE, &KBCacheLimit)) != ERROR_SUCCESS)
goto exit;
// Options.
if ((dwError = roNewVendor.SetValue(CACHE_OPTIONS_VALUE, &dwOptions)) != ERROR_SUCCESS)
goto exit;
}
}
else
{
dwError = ERROR_ALREADY_EXISTS;
}
}
if (fInsertOk)
{
IncrementModifiedCount();
}
exit:
if (pro)
{
delete pro;
}
mh.Release();
if (fInsertOk)
{
GetExtensibleCacheConfigInfo(TRUE);
}
return dwError;
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::FindExtensibleContainer
----------------------------------------------------------------------------*/
// THIS FUNCTION MUST BE CALLED WITH THE CACHE CRIT SECTION
DWORD CConMgr::FindExtensibleContainer(LPCSTR Name)
{
DWORD n = NOT_AN_INDEX;
DWORD i;
URL_CONTAINER *co;
for (i = NCONTAINERS; i < ConList.Size(); i++)
{
co = ConList.Get(i);
if (co)
{
if (!stricmp(Name, co->GetCacheName()) && co->IsVisible())
{
// Found a match
n = i;
co->Release(FALSE);
break;
}
co->Release(FALSE);
}
}
return n;
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::DeleteContainer
----------------------------------------------------------------------------*/
DWORD CConMgr::DeleteContainer(LPCSTR Name, DWORD dwOptions)
{
DWORD dwError = ERROR_SUCCESS;
URL_CONTAINER *co = NULL;
DWORD n = NOT_AN_INDEX;
HKEY hKey;
if (!Name || !*Name)
{
dwError = ERROR_INVALID_PARAMETER;
goto exit;
}
LOCK_CACHE();
n = FindExtensibleContainer(Name);
if (n != NOT_AN_INDEX)
{
co = ConList.Get(n);
if (co)
{
co->SetDeletePending(TRUE);
// Don't release here, hold it pending until we've updated registry
}
}
UNLOCK_CACHE();
if (n!= NOT_AN_INDEX)
{
hKey = (_fProfilesCapable ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE);
REGISTRY_OBJ* pro = CreateExtensiRegObj(hKey);
if (!pro)
{
dwError = ERROR_ACCESS_DENIED;
goto exit;
}
{
REGISTRY_OBJ& roExtensibleCache = *pro;
MUTEX_HOLDER mh;
mh.Grab(_hMutexExtensible, FAILSAFE_TIMEOUT);
dwError = roExtensibleCache.DeleteKey((LPSTR)Name);
mh.Release();
IncrementModifiedCount();
}
delete pro;
}
exit:
LOCK_CACHE();
SAFERELEASE(co, TRUE);
UNLOCK_CACHE();
return dwError;
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::DeleteFileIfNotRegistered
----------------------------------------------------------------------------*/
BOOL CConMgr::DeleteFileIfNotRegistered(URL_CONTAINER *coDelete)
{
BOOL fDelete = TRUE;
BOOL fFound = FALSE;
CHAR szCachePath[MAX_PATH];
CHAR szCachePrefix[MAX_PATH];
DWORD dwOptions;
LONGLONG cbCacheLimit;
HKEY hKey = (HKEY) INVALID_HANDLE_VALUE;
DWORD cbKeyLen, cbKBLimit, dwError;
CHAR szVendorKey[MAX_PATH];
hKey = (_fProfilesCapable ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE);
REGISTRY_OBJ* pro = CreateExtensiRegObj(hKey);
MUTEX_HOLDER mh;
if (!pro)
{
dwError = ERROR_ACCESS_DENIED;
goto exit;
}
if (!WasModified(FALSE))
{
// If our internal cache is up to date, it can't
// have been deleted unless DeletePending or Deleted
fFound = !(coDelete->GetDeletePending()||coDelete->GetDeleted());
if (fFound)
{
goto exit;
}
// If not found, need to look at registry to make sure we're not
// deleting a path that has been reused
}
mh.Grab(_hMutexExtensible, FAILSAFE_TIMEOUT);
{
REGISTRY_OBJ& roExtensibleCache = *pro;
// Get the container paths, prefixes.
while (roExtensibleCache.FindNextKey(szVendorKey, MAX_PATH) == ERROR_SUCCESS)
{
BOOL fPathMatch;
REGISTRY_OBJ roVendor(&roExtensibleCache, szVendorKey);
if (roVendor.GetStatus()==ERROR_SUCCESS)
{
// Path.
TCHAR szScratch[MAX_PATH];
cbKeyLen = MAX_PATH;
if (roVendor.GetValue(CACHE_PATH_VALUE,(LPBYTE) szScratch, &cbKeyLen) != ERROR_SUCCESS)
continue;
ExpandEnvironmentStrings(szScratch, szCachePath, sizeof(szCachePath)-1); // don't count the NULL
// Prefix.
cbKeyLen = MAX_PATH;
if (roVendor.GetValue(CACHE_PREFIX_VALUE,(LPBYTE) szCachePrefix, &cbKeyLen) != ERROR_SUCCESS)
continue;
// Options.
if (roVendor.GetValue(CACHE_OPTIONS_VALUE,&dwOptions) != ERROR_SUCCESS)
continue;
fPathMatch = !stricmp(coDelete->GetCachePath(), szCachePath);
if (!stricmp(coDelete->GetCacheName(), szVendorKey) && fPathMatch &&
!stricmp(coDelete->GetCachePrefix(), szCachePrefix) &&
coDelete->GetOptions() != dwOptions)
{
fFound = TRUE;
}
if (fPathMatch)
fDelete = FALSE;
}
}
}
if (fDelete)
{
// This will fail if another process still has the container mapped,
// that's ok. They will check on exit if container needs to be
// deleted
if (coDelete->GetOptions() & INTERNET_CACHE_CONTAINER_AUTODELETE)
{
CFileMgr::DeleteCache(coDelete->GetCachePath());
}
}
exit:
if (pro)
{
delete pro;
}
mh.Release();
return !fFound;
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::FindIndexFromPrefix
----------------------------------------------------------------------------*/
// THIS FUNCTION MUST BE CALLED WITH THE CACHE CRIT SEC
DWORD CConMgr::FindIndexFromPrefix(LPCSTR szUrl)
{
// Unless we find a matching prefix, CONTENT is the default.
DWORD n = szUrl[0]==EXTENSIBLE_FIRST ? NOT_AN_INDEX : CONTENT;
URL_CONTAINER *co = NULL;
// NOTE: if deleting a container is supported, ConList.Get(i) can
// return NULL, if list shrinks after getting size.
// NOTE: if deleting containers is supported, it is not safe to
// assume CONTENT if prefix is not found. client may be trying to
// insert into a container that has been deleted, but once existed.
// proper response is to return an error. the simplest way to do this
// is to insist that all Extensible cache prefixes start with an illegal
// URL character, EXTENSIBLE_FIRST
GetExtensibleCacheConfigInfo(FALSE);
for (DWORD i = COOKIE; i < ConList.Size(); i++)
{
co = ConList.Get(i);
if (co)
{
if (co->PrefixMatch(szUrl))
{
// For content container, strnicmp (szUrl, "", 0) returns nonzero
if (co->IsVisible())
{
// Found a match
n = i;
if (!co->IsInitialized())
{
// Init the container. If this fails,
// Mark it as DELETED and return CONTENT.
switch (co->Init())
{
case ERROR_SUCCESS:
case ERROR_ALREADY_EXISTS:
if (!(co->GetOptions() & INTERNET_CACHE_CONTAINER_NODESKTOPINIT))
EnableCacheVu(co->GetCachePath(), n);
break;
default:
INET_ASSERT(FALSE);
co->SetDeleted(TRUE);
n = szUrl[0]==EXTENSIBLE_FIRST ? NOT_AN_INDEX : CONTENT;
break;
}
}
co->Release(FALSE);
break;
}
}
co->Release(FALSE);
}
}
return n;
}
/*-----------------------------------------------------------------------------
BOOL CConMgr::PathPrefixMatch
----------------------------------------------------------------------------*/
BOOL CConMgr::PathPrefixMatch(LPCSTR szPath, LPCSTR szPathRef)
{
// BUGBUG - logic borrowed from original cacheapi.cxx
INT len;
// TRUE if the passed in path is NULL
if (!szPath)
return TRUE;
len = lstrlen(szPath);
// TRUE if it is 0 length.
if (!len)
return TRUE;
// stripout the trailing slash
if (szPath[len-1] == DIR_SEPARATOR_CHAR)
--len;
// Compare paths.
if (!strnicmp(szPath, szPathRef, len))
if (szPathRef[len] == DIR_SEPARATOR_CHAR || szPathRef[len] == 0)
return TRUE;
return FALSE;
}
/*--------------------- Public Functions -----------------------------------*/
/*-----------------------------------------------------------------------------
CConMgr::CConMgr
Default Constructor
----------------------------------------------------------------------------*/
CConMgr::CConMgr()
: ConList()
{
_coContent = NULL;
_coCookies = NULL;
_coHistory = NULL;
_hMutexExtensible = 0;
// Assume this is a profiles-capable machine. Later on, we'll make sure this is
// the case.
_fProfilesCapable = TRUE;
// Assume that we'll be using the regular containers, instead of the backup
_fUsingBackupContainers = FALSE;
_dwStatus = Init();
}
/*-----------------------------------------------------------------------------
CConMgr::~CConMgr
Default Destructor
----------------------------------------------------------------------------*/
CConMgr::~CConMgr()
{
ConList.Free();
if (_hMutexExtensible)
{
CloseHandle(_hMutexExtensible);
}
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::GetStatus()
----------------------------------------------------------------------------*/
DWORD CConMgr::GetStatus()
{
return _dwStatus;
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::UnlockUrl
----------------------------------------------------------------------------*/
DWORD CConMgr::UnlockUrl(LPCSTR szUrl)
{
URL_CONTAINER *co;
DWORD dwError = ERROR_FILE_NOT_FOUND;
// Find the associated container.
DWORD idx;
LOCK_CACHE();
idx = FindIndexFromPrefix(szUrl);
co = ConList.Get(idx);
if (co)
{
UNLOCK_CACHE();
// Call UnlockUrl on the appropriate container.
dwError = co->UnlockUrl(szUrl); // may be expensive
LOCK_CACHE();
co->Release(TRUE);
}
UNLOCK_CACHE();
return dwError;
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::DeleteUrl
----------------------------------------------------------------------------*/
DWORD CConMgr::DeleteUrl(LPCSTR szUrl)
{
URL_CONTAINER *co;
DWORD dwError = ERROR_FILE_NOT_FOUND;
// Find the associated container.
DWORD idx;
UNIX_RETURN_ERR_IF_READONLY_CACHE(dwError);
LOCK_CACHE();
idx = FindIndexFromPrefix(szUrl);
co = ConList.Get(idx);
if (co)
{
UNLOCK_CACHE();
// Call DeleteUrl on the appropriate container.
dwError = co->DeleteUrl(szUrl); // may be expensive.
LOCK_CACHE();
co->Release(TRUE);
// Update the change count for the cookies container.
if (idx == COOKIE)
{
DWORD dwChange = 0;
_coContent->IncrementHeaderData(CACHE_HEADER_DATA_COOKIE_CHANGE_COUNT, &dwChange);
}
}
UNLOCK_CACHE();
return dwError;
}
/*-----------------------------------------------------------------------------
BOOL CConMgr::GetHeaderData
----------------------------------------------------------------------------*/
BOOL CConMgr::GetHeaderData(DWORD nIdx, LPDWORD pdwData)
{
return _coContent->GetHeaderData(nIdx, pdwData);
}
/*-----------------------------------------------------------------------------
BOOL CConMgr::SetHeaderData
----------------------------------------------------------------------------*/
BOOL CConMgr::SetHeaderData(DWORD nIdx, DWORD dwData)
{
UNIX_RETURN_ERR_IF_READONLY_CACHE(FALSE);
return _coContent->SetHeaderData(nIdx, dwData);
}
/*-----------------------------------------------------------------------------
BOOL CConMgr::IncrementHeaderData
----------------------------------------------------------------------------*/
BOOL CConMgr::IncrementHeaderData(DWORD nIdx, LPDWORD pdwData)
{
UNIX_RETURN_ERR_IF_READONLY_CACHE(FALSE);
return _coContent->IncrementHeaderData(nIdx, pdwData);
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::SetUrlGroup
----------------------------------------------------------------------------*/
DWORD CConMgr::SetUrlGroup(
IN LPCSTR szUrl,
IN DWORD dwFlags,
IN GROUPID GroupId
)
{
URL_CONTAINER *co;
DWORD dwError = ERROR_FILE_NOT_FOUND;
// Find the associated container.
UNIX_RETURN_ERR_IF_READONLY_CACHE(dwError);
LOCK_CACHE();
DWORD idx = FindIndexFromPrefix(szUrl);
co = ConList.Get(idx);
if (co)
{
UNLOCK_CACHE();
// Call SetUrlInGroup on the appropriate container.
dwError = co->SetUrlGroup
(szUrl, dwFlags, GroupId);
LOCK_CACHE();
co->Release(TRUE);
}
UNLOCK_CACHE();
return dwError;
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::CreateUniqueFile
----------------------------------------------------------------------------*/
DWORD CConMgr::CreateUniqueFile(LPCSTR szUrl, DWORD dwExpectedSize,
LPCSTR szFileExtension, LPTSTR szFileName,
HANDLE *phfHandle,
BOOL fCreatePerUser)
{
URL_CONTAINER *co;
DWORD dwError = ERROR_FILE_NOT_FOUND;
// Find the associated container.
UNIX_RETURN_ERR_IF_READONLY_CACHE(dwError);
LOCK_CACHE();
DWORD idx = FindIndexFromPrefix(szUrl);
co = ConList.Get(idx);
if (co)
{
UNLOCK_CACHE();
// Call CreateUniqueFile on the appropriate container.
dwError = co->CreateUniqueFile(szUrl, dwExpectedSize,
szFileExtension, szFileName, phfHandle, fCreatePerUser); // expensive call
LOCK_CACHE();
co->Release(TRUE);
}
UNLOCK_CACHE();
return dwError;
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::AddUrl
----------------------------------------------------------------------------*/
DWORD CConMgr::AddUrl(AddUrlArg* pArgs)
{
URL_CONTAINER *co;
DWORD dwError = ERROR_FILE_NOT_FOUND;
// Find the associated container.
UNIX_RETURN_ERR_IF_READONLY_CACHE(dwError);
LOCK_CACHE();
DWORD idx = FindIndexFromPrefix(pArgs->pszUrl);
co = ConList.Get(idx);
if (co)
{
UNLOCK_CACHE();
// Call AddUrl on the appropriate container.
dwError = co->AddUrl(pArgs); // may be expensive
LOCK_CACHE();
co->Release(TRUE);
// Update the change count for the cookies container.
if (idx == COOKIE)
{
DWORD dwChange = 0;
_coContent->IncrementHeaderData(CACHE_HEADER_DATA_COOKIE_CHANGE_COUNT, &dwChange);
}
}
UNLOCK_CACHE();
return dwError;
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::RetrieveUrl
----------------------------------------------------------------------------*/
DWORD CConMgr::RetrieveUrl( LPCSTR szUrl,
LPCACHE_ENTRY_INFOA* ppCacheEntryInfo,
LPDWORD pcbCacheEntryInfoBufferSize,
DWORD dwLookupFlags,
DWORD dwRetrievalFlags)
{
URL_CONTAINER *co;
DWORD dwError = ERROR_FILE_NOT_FOUND;
// Find the associated container.
LOCK_CACHE();
DWORD idx = FindIndexFromPrefix(szUrl);
co = ConList.Get(idx);
if (co)
{
UNLOCK_CACHE();
// Call RetrieveUrl on the appropriate container.
dwError = co->RetrieveUrl(szUrl,
ppCacheEntryInfo,
pcbCacheEntryInfoBufferSize,
dwLookupFlags, dwRetrievalFlags); // expensive?
LOCK_CACHE();
co->Release(TRUE);
}
UNLOCK_CACHE();
return dwError;
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::GetUrlInfo
----------------------------------------------------------------------------*/
DWORD CConMgr::GetUrlInfo( LPCSTR szUrl,
LPCACHE_ENTRY_INFOA* ppCacheEntryInfo,
LPDWORD pcbCacheEntryInfoBufferSize,
DWORD dwLookupFlags,
DWORD dwEntryFlags,
DWORD dwRetrievalFlags)
{
URL_CONTAINER *co;
DWORD dwError = ERROR_FILE_NOT_FOUND;
// Find the associated container.
LOCK_CACHE();
DWORD idx = FindIndexFromPrefix(szUrl);
co = ConList.Get(idx);
if (co)
{
// Call GetUrlInfo on the appropriate container.
dwError = co->GetUrlInfo(szUrl,
ppCacheEntryInfo,
pcbCacheEntryInfoBufferSize,
dwLookupFlags,
dwEntryFlags,
dwRetrievalFlags);
co->Release(TRUE);
}
UNLOCK_CACHE();
return dwError;
}
DWORD CConMgr::GetUrlInfo(LPCSTR szUrl,
LPCACHE_ENTRY_INFOA pCacheEntryInfo,
LPDWORD pcbCacheEntryInfoBufferSize,
DWORD dwLookupFlags,
DWORD dwEntryFlags)
{
return GetUrlInfo(szUrl,
(pCacheEntryInfo) ? &pCacheEntryInfo : NULL,
pcbCacheEntryInfoBufferSize,
dwLookupFlags,
dwEntryFlags,
0);
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::SetUrlInfo
----------------------------------------------------------------------------*/
DWORD CConMgr::SetUrlInfo(LPCSTR szUrl,
LPCACHE_ENTRY_INFOA pCacheEntryInfo,
DWORD dwFieldControl)
{
URL_CONTAINER *co;
DWORD dwError = ERROR_FILE_NOT_FOUND;
// Find the associated container.
UNIX_RETURN_ERR_IF_READONLY_CACHE(dwError);
LOCK_CACHE();
DWORD idx = FindIndexFromPrefix(szUrl);
co = ConList.Get(idx);
if (co)
{
// Call SetUrlInfo on the appropriate container.
dwError = co->SetUrlInfo(szUrl,
pCacheEntryInfo,
dwFieldControl);
co->Release(TRUE);
}
UNLOCK_CACHE();
return dwError;
}
DWORD CConMgr::FreeFindHandle(HANDLE hFind)
{
DWORD dwError = ERROR_INVALID_HANDLE;
if (hFind)
{
LOCK_CACHE();
LPCACHE_FIND_FIRST_HANDLE pFind;
pFind = (CACHE_FIND_FIRST_HANDLE*) HandleMgr.Map (hFind);
if (pFind)
{
// NOTHING SPECIAL TO DO FOR SIGNATURE_CONTAINER_FIND
if (pFind->dwSig == SIG_CACHE_FIND && !pFind->fFixed)
{
URL_CONTAINER *co = ConList.Get(pFind->nIdx);
if (co)
{
// It now has 2 AddRefs to balance
co->Release(FALSE);
co->Release(TRUE);
}
}
HandleMgr.Free (hFind);
dwError = ERROR_SUCCESS;
}
UNLOCK_CACHE();
}
return dwError;
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::FindNextEntry
----------------------------------------------------------------------------*/
DWORD CConMgr::FindNextEntry(
HANDLE *phFind,
LPCSTR szPrefix,
LPCACHE_ENTRY_INFOA* ppInfo,
LPDWORD pcbInfo,
DWORD dwFilter,
GROUPID GroupId,
DWORD dwFlags,
DWORD dwRetrievalFlags)
{
DWORD idx, dwError;
URL_CONTAINER *co = NULL;
LPCACHE_FIND_FIRST_HANDLE pFind = NULL;
LOCK_CACHE();
// Null handle initiates enumeration.
if (!*phFind)
{
// Allocate a handle.
//LOCK_CACHE();
*phFind = HandleMgr.Alloc (sizeof(CACHE_FIND_FIRST_HANDLE));
if (*phFind)
pFind = (CACHE_FIND_FIRST_HANDLE*) HandleMgr.Map (*phFind);
//UNLOCK_CACHE();
if (!*phFind)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
goto exit;
}
if (!pFind)
{
dwError = ERROR_INVALID_HANDLE;
goto exit;
}
// Set signature and initial hash table find
// handle in the newly allocated find handle.
pFind->dwSig = SIG_CACHE_FIND;
pFind->dwHandle = 0;
pFind->dwFlags = dwFlags;
// Find the associated container. NULL prefix
// results in enumeration over fixed containers.
if (!szPrefix)
{
pFind->fFixed = TRUE;
pFind->nIdx = CONTENT;
}
else
{
idx = FindIndexFromPrefix(szPrefix);
if (idx == NOT_AN_INDEX)
{
dwError = ERROR_NO_MORE_ITEMS;
goto exit;
}
// Under old semantics prefix resolving to CONTENT
// container implies that an enumeration over all
// the fixed containers is desired. Enumeration then
// begins with the CONTENT container. We do not keep
// a refcount on any fixed containers in this case.
if (idx == CONTENT && (dwFlags & FIND_FLAGS_OLD_SEMANTICS))
{
pFind->fFixed = TRUE;
pFind->nIdx = CONTENT;
}
else
{
// Otherwise only enumeration over the found container
// is implied. Retrieve this container. Set fFixed to FALSE.
// NO RELEASE: hold RefCnt until handle is closed
co = ConList.Get(idx);
if (co)
{
pFind->fFixed = FALSE;
pFind->nIdx = idx;
pFind->dwHandle = co->GetInitialFindHandle();
}
else
{
dwError = ERROR_NO_MORE_ITEMS;
goto exit;
}
}
}
// Set filter and group id in handle.
pFind->dwFilter = dwFilter;
pFind->GroupId = GroupId;
}
else
{
// Valid handle passed in - map it.
//LOCK_CACHE();
pFind = (CACHE_FIND_FIRST_HANDLE*) HandleMgr.Map (*phFind);
//UNLOCK_CACHE();
if (!pFind)
{
dwError = ERROR_INVALID_HANDLE;
goto exit;
}
}
// -------------------------------------------------------------------------
// The handle is initialized or was created via a previous FindNextEntry.
//--------------------------------------------------------------------------
dwError = ERROR_NO_MORE_ITEMS;
// Are we only enumerating over one container?
if (!pFind->fFixed)
{
// Get the associated container.
co = ConList.Get(pFind->nIdx);
if (co)
{
// Enum on the container and release.
dwError = co->FindNextEntry(&pFind->dwHandle, ppInfo, pcbInfo, pFind->dwFilter, pFind->GroupId, pFind->dwFlags, dwRetrievalFlags);
co->Release(TRUE);
}
else
{
// Getting container failed.
dwError = ERROR_NO_MORE_ITEMS;
goto exit;
}
}
else
{
// fFixed is TRUE - enumerate over the fixed containers.
while (pFind->nIdx < NCONTAINERS)
{
// Get the associated container.
co = ConList.Get(pFind->nIdx);
if (co)
{
// Get the initial hash find handle if not already done so.
if (!pFind->dwHandle)
pFind->dwHandle = co->GetInitialFindHandle();
// Enum on the container and release.
dwError = co->FindNextEntry(&pFind->dwHandle, ppInfo, pcbInfo, pFind->dwFilter, pFind->GroupId, pFind->dwFlags, dwRetrievalFlags);
co->Release(TRUE);
// Goto exit only if ERROR_NO_MORE_ITEMS.
// This handles ERROR_SUCCESS correctly.
if (dwError != ERROR_NO_MORE_ITEMS)
goto exit;
// ERROR_NO_MORE_ITEMS: Go to next container
// and begin enum anew.
pFind->nIdx++;
pFind->dwHandle = 0;
}
else
{
// Getting container failed.
dwError = ERROR_NO_MORE_ITEMS;
goto exit;
}
}
}
exit:
UNLOCK_CACHE();
INET_ASSERT(*phFind != 0);
INET_ASSERT(pFind != NULL);
return dwError;
}
DWORD CConMgr::FindNextEntry(
HANDLE *phFind,
LPCSTR szPrefix,
LPCACHE_ENTRY_INFOA pInfo,
LPDWORD pcbInfo,
DWORD dwFilter,
GROUPID GroupId,
DWORD dwFlags)
{
return FindNextEntry(
phFind,
szPrefix,
(pInfo ? &pInfo : NULL),
pcbInfo,
dwFilter,
GroupId,
dwFlags,
0);
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::CleanupUrls
----------------------------------------------------------------------------*/
DWORD CConMgr::CleanupUrls
(LPCTSTR szCachePath, DWORD dwFactor, DWORD dwFilter)
{
DWORD dwError = ERROR_SUCCESS;
UNIX_RETURN_ERR_IF_READONLY_CACHE(dwError);
// Bad cleanup parameter.
if (dwFactor <= 0 || dwFactor > 100)
{
dwError = ERROR_INVALID_PARAMETER;
goto exit;
}
// For null or empty path, clean up content container.
if (!szCachePath || !*szCachePath)
{
_coContent->CleanupUrls(dwFactor, dwFilter);
}
else
{
LOCK_CACHE();
// Find the container with the matching cache path and clean it up.
for (DWORD idx = CONTENT; idx < NCONTAINERS; idx++)
{
URL_CONTAINER *co = ConList.Get(idx);
if (co)
{
if (PathPrefixMatch(szCachePath, co->GetCachePath()))
{
UNLOCK_CACHE();
co->CleanupUrls(dwFactor, dwFilter); // expensive?
LOCK_CACHE();
co->Release(TRUE);
break;
}
co->Release(TRUE);
}
}
UNLOCK_CACHE();
}
exit:
return dwError;
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::GetUrlInGroup
----------------------------------------------------------------------------*/
DWORD CConMgr::GetUrlInGroup(LPCSTR szUrl, GROUPID* pGroupId, LPDWORD pdwExemptDelta)
{
URL_CONTAINER *co;
DWORD dwError = ERROR_FILE_NOT_FOUND;
// Find the associated container.
LOCK_CACHE();
DWORD idx = FindIndexFromPrefix(szUrl);
co = ConList.Get(idx);
if (co)
{
UNLOCK_CACHE();
// Call GetUrlInGroup on the appropriate container.
dwError = co->GetUrlInGroup(szUrl, pGroupId, pdwExemptDelta);
LOCK_CACHE();
co->Release(TRUE);
}
UNLOCK_CACHE();
return dwError;
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::CreateGroup()
----------------------------------------------------------------------------*/
DWORD CConMgr::CreateGroup(DWORD dwFlags, GROUPID* pGID)
{
INET_ASSERT(_coContent);
LOCK_CACHE();
GroupMgr gm;
DWORD dwError = ERROR_WINHTTP_INTERNAL_ERROR;
if( gm.Init(_coContent) )
{
dwError = gm.CreateGroup(dwFlags, pGID);
}
UNLOCK_CACHE();
return dwError;
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::CreateDefaultGroups()
----------------------------------------------------------------------------*/
DWORD CConMgr::CreateDefaultGroups()
{
INET_ASSERT(_coContent);
LOCK_CACHE();
GroupMgr gm;
DWORD dwError = ERROR_WINHTTP_INTERNAL_ERROR;
if( gm.Init(_coContent) )
{
dwError = gm.CreateDefaultGroups();
}
UNLOCK_CACHE();
return dwError;
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::DeleteGroup()
----------------------------------------------------------------------------*/
DWORD CConMgr::DeleteGroup(GROUPID gid, DWORD dwFlags)
{
INET_ASSERT(_coContent);
LOCK_CACHE();
GroupMgr gm;
DWORD dwError = ERROR_WINHTTP_INTERNAL_ERROR;
if( gm.Init(_coContent) )
{
dwError = gm.DeleteGroup(gid, dwFlags);
}
UNLOCK_CACHE();
return dwError;
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::FindNextGroup()
----------------------------------------------------------------------------*/
DWORD CConMgr::FindNextGroup(
HANDLE* phFind,
DWORD dwFlags,
GROUPID* pGroupId
)
{
DWORD dwError;
GROUP_FIND_FIRST_HANDLE* pFind = NULL;
GroupMgr gm;
INET_ASSERT(_coContent);
LOCK_CACHE();
// Null handle initiates enumeration.
if (!*phFind)
{
// BUGBUG currently only supports SEARCH_ALL option
if( dwFlags )
{
dwError = ERROR_INVALID_PARAMETER;
goto exit;
}
// Allocate a handle.
*phFind = HandleMgr.Alloc (sizeof(GROUP_FIND_FIRST_HANDLE));
if (*phFind)
pFind = (GROUP_FIND_FIRST_HANDLE*) HandleMgr.Map (*phFind);
if (!*phFind)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
goto exit;
}
if (!pFind)
{
dwError = ERROR_INVALID_HANDLE;
goto exit;
}
// Set signature and initial hash table find
// handle in the newly allocated find handle.
pFind->dwSig = SIG_GROUP_FIND;
pFind->fFixed = TRUE;
pFind->nIdx = CONTENT;
pFind->dwLastItemOffset = 0;
}
else
{
// Valid handle passed in - map it.
pFind = (GROUP_FIND_FIRST_HANDLE*) HandleMgr.Map (*phFind);
if (!pFind)
{
dwError = ERROR_INVALID_HANDLE;
goto exit;
}
}
//
// The handle is initialized or was created via a previous FindNextEntry.
//
dwError = ERROR_FILE_NOT_FOUND;
// Enum on the container and release.
if( gm.Init(_coContent) )
{
DWORD dwLastItemOffset = pFind->dwLastItemOffset;
dwError = gm.GetNextGroup(&dwLastItemOffset, pGroupId);
// update offset field of the find handle
pFind->dwLastItemOffset = dwLastItemOffset;
}
exit:
UNLOCK_CACHE();
INET_ASSERT(*phFind != 0);
INET_ASSERT(pFind != NULL);
return dwError;
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::GetGroupAttributes()
----------------------------------------------------------------------------*/
DWORD CConMgr::GetGroupAttributes(
GROUPID gid,
DWORD dwAttrib,
LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
LPDWORD lpdwGroupInfo
)
{
INET_ASSERT(_coContent);
DWORD dwError = ERROR_WINHTTP_INTERNAL_ERROR;
LOCK_CACHE();
GroupMgr gm;
if( gm.Init(_coContent) )
{
dwError = gm.GetGroup(gid, dwAttrib, lpGroupInfo, lpdwGroupInfo);
}
UNLOCK_CACHE();
return dwError;
}
/*-----------------------------------------------------------------------------
DWORD CConMgr::SetGroupAttributes()
----------------------------------------------------------------------------*/
DWORD CConMgr::SetGroupAttributes(
GROUPID gid,
DWORD dwAttrib,
LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo
)
{
INET_ASSERT(_coContent);
DWORD dwError = ERROR_WINHTTP_INTERNAL_ERROR;
LOCK_CACHE();
GroupMgr gm;
if( gm.Init(_coContent))
{
dwError = gm.SetGroup(gid, dwAttrib, lpGroupInfo);
}
UNLOCK_CACHE();
return dwError;
}
DWORD CConMgr::RegisterCacheNotify(
HWND hWnd,
UINT uMsg,
GROUPID gid,
DWORD dwFilter
)
{
DWORD dwError;
INET_ASSERT(_coContent);
dwError = _coContent->RegisterCacheNotify(hWnd, uMsg, gid, dwFilter);
return dwError;
}
DWORD CConMgr::SendCacheNotification( DWORD dwOp)
{
DWORD dwError;
INET_ASSERT(_coContent);
_coContent->SendCacheNotification(dwOp);
return ERROR_SUCCESS;
}
/*-----------------------------------------------------------------------------
VOID CConMgr::GetCacheInfo
----------------------------------------------------------------------------*/
VOID CConMgr::GetCacheInfo(LPCSTR szPrefix, LPSTR szCachePath, LONGLONG *cbLimit)
{
URL_CONTAINER *co;
// Find the associated container.
LOCK_CACHE();
DWORD idx = FindIndexFromPrefix(szPrefix);
co = ConList.Get(idx);
if (co)
{
// Call GetCacheInfo on the appropriate container.
co->GetCacheInfo(szCachePath, cbLimit);
co->Release(TRUE);
}
UNLOCK_CACHE();
}
/*-----------------------------------------------------------------------------
VOID CConMgr::SetCacheLimit
----------------------------------------------------------------------------*/
VOID CConMgr::SetCacheLimit(LONGLONG cbLimit, DWORD idx)
{
URL_CONTAINER *co;
// Find the associated container.
UNIX_RETURN_IF_READONLY_CACHE;
LOCK_CACHE();
co = ConList.Get(idx);
if (co)
{
// Call SetCacheLimit on the container.
co->SetCacheLimit(cbLimit);
co->Release(TRUE);
}
UNLOCK_CACHE();
}