/*++ Copyright (c) 1997 Microsoft Corporation Module Name: conmgr.cxx Abstract: Manages list of containers (CConList) Author: Adriaan Canter (adriaanc) 04-02-97 --*/ #include #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_INTERNET_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_INTERNET_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_INTERNET_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_INTERNET_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_INTERNET_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_INTERNET_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_INTERNET_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_INTERNET_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_INTERNET_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(); }