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.
2553 lines
87 KiB
2553 lines
87 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cachecfg.cxx
|
|
|
|
Abstract:
|
|
|
|
This module contains the functions to get and set disk cache
|
|
configuration parameters.
|
|
|
|
Contents:
|
|
GetCacheConfigInfoA
|
|
SetCacheConfigInfoA
|
|
|
|
Author:
|
|
|
|
Sophia Chung (sophiac) 1-May-1995
|
|
|
|
Environment:
|
|
|
|
User Mode - Win32
|
|
|
|
Revision History:
|
|
Mucho rewritten by Akabir 1Q 98
|
|
|
|
To understand how the new registration code works, it might be better for you to start with ConfigureCache,
|
|
GetCacheConfigInfo, etc. for a high level acquaintance; _then_ start poring over the actual registry sets code.
|
|
--*/
|
|
|
|
#include <cache.hxx>
|
|
#include <conmgr.hxx>
|
|
#include <time.h>
|
|
|
|
#include <shlobj.h>
|
|
|
|
#define CACHE_TAG "Cache"
|
|
|
|
// Cache path keys.
|
|
CHAR* g_szSubKey[] = {CONTENT_PATH_KEY, COOKIE_PATH_KEY, HISTORY_PATH_KEY};
|
|
CHAR* g_szOldSubKey[] = {CACHE_TAG, COOKIE_PATH_KEY, HISTORY_PATH_KEY};
|
|
|
|
INT g_iContainerCSIDL[] = { CSIDL_INTERNET_CACHE, CSIDL_COOKIES, CSIDL_HISTORY };
|
|
|
|
// Top level cache paths resource IDs
|
|
#ifndef UNIX
|
|
DWORD g_dwCachePathResourceID[] = {IDS_CACHE_DEFAULT_SUBDIR, IDS_COOKIES_DEFAULT_SUBDIR, IDS_HISTORY_DEFAULT_SUBDIR};
|
|
#else
|
|
DWORD g_dwCachePathResourceID[] = {IDS_CACHE_DEFAULT_SUBDIR_UNIX, IDS_COOKIES_DEFAULT_SUBDIR, IDS_HISTORY_DEFAULT_SUBDIR};
|
|
#endif /* UNIX */
|
|
|
|
// Cache prefixes.
|
|
CHAR* g_szCachePrefix[] = {CONTENT_PREFIX, COOKIE_PREFIX, HISTORY_PREFIX};
|
|
CHAR* g_szVersionName[] = { CONTENT_VERSION_SUBDIR, "", "History.IE5" };
|
|
|
|
#define OLD_CACHE_PATH "Path1"
|
|
#define OLD_CACHE_SUBKEY DIR_SEPARATOR_STRING##"Cache1"
|
|
|
|
typedef BOOL (WINAPI *PFNGETDISKFREESPACEEX)(LPCTSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER);
|
|
|
|
void FlushShellFolderCache()
|
|
{
|
|
SHFlushSFCacheWrap( );
|
|
return;
|
|
}
|
|
|
|
typedef HRESULT (*PFNSHGETFOLDERPATH)(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPSTR pszPath);
|
|
|
|
VOID CheckCacheLocationConsistency();
|
|
|
|
//#define DEBUG_CACHE_UPGRADE
|
|
|
|
#ifdef DEBUG_CACHE_UPGRADE
|
|
VOID LOG_UPGRADE_DATA(PTSTR pszData)
|
|
{
|
|
CHAR szFileName[MAX_PATH];
|
|
DWORD dwSize = MAX_PATH;
|
|
CHAR szComputerName[MAX_PATH];
|
|
HANDLE hResultsFile = NULL;
|
|
strcpy(szFileName, "\\\\BANYAN\\IPTD\\AKABIR\\cacheupgrade\\");
|
|
if (!GetComputerNameA(szComputerName, &dwSize))
|
|
{
|
|
goto exit;
|
|
}
|
|
lstrcatA(szFileName, szComputerName);
|
|
hResultsFile = CreateFileA( szFileName,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_WRITE | FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_ALWAYS,
|
|
0,
|
|
NULL);
|
|
if (hResultsFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (SetFilePointer(hResultsFile, 0, NULL, FILE_END)==0xFFFFFFFF)
|
|
{
|
|
goto exit;
|
|
}
|
|
DWORD dwFoo;
|
|
if (0==WriteFile(hResultsFile, (PVOID)pszData, lstrlenA(pszData), &dwFoo, NULL))
|
|
{
|
|
DWORD dwE = GetLastError();
|
|
}
|
|
}
|
|
exit:
|
|
if (hResultsFile)
|
|
{
|
|
CloseHandle(hResultsFile);
|
|
}
|
|
}
|
|
#else
|
|
#define LOG_UPGRADE_DATA(x)
|
|
#endif
|
|
|
|
#undef SHGetFolderPath
|
|
|
|
HRESULT SHGetFolderPath(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPSTR pszPath)
|
|
{
|
|
HRESULT hr = E_POINTER;
|
|
static PFNSHGETFOLDERPATH pfn = NULL;
|
|
|
|
if (NULL == pfn)
|
|
{
|
|
if (NULL == g_HMODShell32)
|
|
g_HMODShell32 = LoadLibrary("shell32.dll");
|
|
if (NULL != g_HMODShell32)
|
|
pfn = (PFNSHGETFOLDERPATH)GetProcAddress(g_HMODShell32, "SHGetFolderPathA");
|
|
|
|
if (NULL == pfn)
|
|
{
|
|
if (NULL == g_HMODSHFolder)
|
|
g_HMODSHFolder = LoadLibrary("shfolder.dll");
|
|
if (NULL != g_HMODSHFolder)
|
|
pfn = (PFNSHGETFOLDERPATH)GetProcAddress(g_HMODSHFolder, "SHGetFolderPathA");
|
|
}
|
|
|
|
if (NULL != pfn)
|
|
hr = pfn(hwnd, csidl, hToken, dwFlags, pszPath);
|
|
}
|
|
else
|
|
hr = pfn(hwnd, csidl, hToken, dwFlags, pszPath);
|
|
|
|
return hr;
|
|
}
|
|
|
|
#define CACHE_SIZE_CAP 32000000
|
|
|
|
DWORD
|
|
GetDefaultCacheQuota(
|
|
LPSTR pszCachePath,
|
|
DWORD dwFraction
|
|
)
|
|
{
|
|
DWORDLONG cKBLimit = 0, cbTotal;
|
|
|
|
if (GetDiskInfo(pszCachePath, NULL, NULL, &cbTotal))
|
|
{
|
|
cKBLimit = (cbTotal / (DWORDLONG)(1024*dwFraction));
|
|
}
|
|
if (cKBLimit<1024)
|
|
{
|
|
cKBLimit = DEF_CACHE_LIMIT;
|
|
}
|
|
else if (cKBLimit > CACHE_SIZE_CAP)
|
|
{
|
|
cKBLimit = CACHE_SIZE_CAP;
|
|
}
|
|
|
|
return (DWORD)cKBLimit;
|
|
}
|
|
|
|
VOID CleanPath(PTSTR pszPath);
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
NormalisePath
|
|
(code swiped from shell32\folder.c: UnexpandEnvironmentstring)
|
|
|
|
Collapses paths of the form C:\foobar\dir1\...\dirn to
|
|
%FOOBAR%\dir1\...\dirn
|
|
where %FOOBAR% = "C:\foobar".
|
|
storing result in pszOut.
|
|
|
|
If collapse is not possible, returns FALSE and path is unchanged.
|
|
If the given environment variable exists as the first part of the path,
|
|
then the environment variable is inserted into the output buffer.
|
|
|
|
Returns TRUE if pszResult is filled in.
|
|
Example: Input -- C:\WINNT\SYSTEM32\FOO.TXT -and- lpEnvVar = %SystemRoot%
|
|
Output -- %SystemRoot%\SYSTEM32\FOO.TXT
|
|
|
|
---------------------------------------------------------------------------*/
|
|
|
|
|
|
BOOL NormalisePath(LPCTSTR pszPath, LPCTSTR pszEnvVar, LPTSTR pszResult, UINT cbResult)
|
|
{
|
|
TCHAR szEnvVar[MAX_PATH];
|
|
// DWORD dwEnvVar = ExpandEnvironmentStrings(pszEnvVar, szEnvVar, sizeof(szEnvVar)) - 1; // don't count the NULL
|
|
// akabir: a curious bug? causes ExpandEnvironmentStrings to return twice the number of characters.
|
|
|
|
ExpandEnvironmentStrings(pszEnvVar, szEnvVar, sizeof(szEnvVar)-1); // don't count the NULL
|
|
DWORD dwEnvVar = lstrlen(szEnvVar);
|
|
|
|
if (CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, szEnvVar, dwEnvVar, pszPath, dwEnvVar) == 2)
|
|
{
|
|
if (lstrlen(pszPath) + dwEnvVar < cbResult)
|
|
{
|
|
strncpy(pszResult, pszEnvVar, MAX_PATH);
|
|
strncat(pszResult, pszPath + dwEnvVar, MAX_PATH);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
VOID CompressPath(LPTSTR pszSrc, LPTSTR pszDest)
|
|
{
|
|
if (!NormalisePath(pszSrc, TEXT("%USERPROFILE%"), pszDest, MAX_PATH))
|
|
{
|
|
if (!NormalisePath(pszSrc, TEXT("%SystemRoot%"), pszDest, MAX_PATH))
|
|
{
|
|
strncpy(pszDest, pszSrc, MAX_PATH);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// IE 3, 4 and 5 have different registry settings. These classes help ensure they all stay in sync.
|
|
|
|
|
|
// -- IE5's registry set ------------------------------------------------------------------------------------------------
|
|
// *** If using multiple registry sets, use InitialiseKeys for IE5 first.***
|
|
// This is to ensure that profiles-capabilities are noted.
|
|
|
|
class IE5_REGISTRYSET
|
|
{
|
|
protected:
|
|
REGISTRY_OBJ m_roHKLMCache, m_roHKCUCache, m_roShellFolder, m_roUserShellFolder, m_roWorking;
|
|
BOOL m_fProfiles;
|
|
BOOL m_fWorkingPerUser;
|
|
TCHAR m_szSharedPath[MAX_PATH];
|
|
TCHAR m_szProfilePath[MAX_PATH];
|
|
DWORD cbP, cbS, m_dwWorking;
|
|
BOOL m_fInitialised;
|
|
|
|
DWORD InitCommonKeys(BOOL fProfilesCapable, LPSTR pszReg)
|
|
{
|
|
DWORD dwError, dwFlag = CREATE_KEY_IF_NOT_EXISTS;
|
|
|
|
m_fProfiles = fProfilesCapable;
|
|
// Shared item info are located in HKLM/[...]/Internet Settings/5.0/Cache/*
|
|
m_roHKLMCache.WorkWith(HKEY_LOCAL_MACHINE, pszReg, dwFlag);
|
|
if (dwError = m_roHKLMCache.GetStatus()!=ERROR_SUCCESS)
|
|
{
|
|
m_roHKLMCache.WorkWith(HKEY_LOCAL_MACHINE, pszReg, dwFlag, BASIC_ACCESS);
|
|
if (dwError = m_roHKLMCache.GetStatus()!=ERROR_SUCCESS)
|
|
goto exit;
|
|
}
|
|
|
|
m_roShellFolder.WorkWith(HKEY_CURRENT_USER, SHELL_FOLDER_KEY, dwFlag);
|
|
if (dwError = m_roShellFolder.GetStatus()!=ERROR_SUCCESS)
|
|
goto exit;
|
|
|
|
if (fProfilesCapable)
|
|
{
|
|
m_roHKCUCache.WorkWith(HKEY_CURRENT_USER, pszReg, dwFlag);
|
|
if (dwError = m_roHKCUCache.GetStatus()!=ERROR_SUCCESS)
|
|
goto exit;
|
|
}
|
|
|
|
m_roUserShellFolder.WorkWith(HKEY_CURRENT_USER, USER_SHELL_FOLDER_KEY, dwFlag);
|
|
dwError = m_roUserShellFolder.GetStatus();
|
|
if (dwError==ERROR_SUCCESS)
|
|
{
|
|
m_fInitialised = TRUE;
|
|
}
|
|
// Per-user items are located in HKCU/[...]/Explorer/Shell Folders and /Internet Settings/[5.0/]Cache/*
|
|
exit:
|
|
return dwError;
|
|
}
|
|
|
|
virtual BOOL DetermineKeyPlacing(DWORD dwWhich)
|
|
{
|
|
// Determine if this is a per-user item
|
|
// HKCU overrides HKLM
|
|
// If any of the following fail, for content, we'll default to shared.
|
|
|
|
if (!m_fProfiles)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
DWORD dwTemp;
|
|
REGISTRY_OBJ roCUContainer(&m_roHKCUCache, g_szSubKey[dwWhich], CREATE_KEY_IF_NOT_EXISTS);
|
|
if ((roCUContainer.GetStatus()==ERROR_SUCCESS)
|
|
&&
|
|
(roCUContainer.GetValue(PER_USER_KEY, &dwTemp)==ERROR_SUCCESS))
|
|
{
|
|
return dwTemp;
|
|
}
|
|
|
|
REGISTRY_OBJ roLMContainer(&m_roHKLMCache, g_szSubKey[dwWhich], CREATE_KEY_IF_NOT_EXISTS);
|
|
BOOL fPerUser = FALSE;
|
|
|
|
if ((roLMContainer.GetStatus()==ERROR_SUCCESS)
|
|
&&
|
|
(roLMContainer.GetValue(PER_USER_KEY, &dwTemp)==ERROR_SUCCESS))
|
|
{
|
|
return dwTemp;
|
|
}
|
|
|
|
// On NT, the default will be a per-user container.
|
|
#ifndef UNIX
|
|
dwTemp = (GlobalPlatformType == PLATFORM_TYPE_WINNT) ? TRUE : (dwWhich!=CONTENT);
|
|
#else
|
|
dwTemp = (GlobalPlatformType == PLATFORM_TYPE_UNIX) ? TRUE : (dwWhich!=CONTENT);
|
|
#endif /* UNIX */
|
|
|
|
roLMContainer.SetValue(PER_USER_KEY, &dwTemp);
|
|
roCUContainer.SetValue(PER_USER_KEY, &dwTemp);
|
|
return (BOOL)dwTemp;
|
|
}
|
|
|
|
|
|
// -- ValidatePath ------
|
|
// We always assume we've been given a valid path, but we have to test that it's there
|
|
// and available.
|
|
BOOL ValidatePath(PSTR pszPath)
|
|
{
|
|
DWORD dwAttribute = GetFileAttributes(pszPath);
|
|
if (dwAttribute==0xFFFFFFFF)
|
|
{
|
|
// We assume that the directory just isn't there. So we create it.
|
|
hConstructSubDirs(pszPath);
|
|
dwAttribute = GetFileAttributes(pszPath);
|
|
}
|
|
if ((dwAttribute==0xFFFFFFFF)
|
|
||
|
|
(dwAttribute & FILE_ATTRIBUTE_READONLY)
|
|
||
|
|
(!(dwAttribute & FILE_ATTRIBUTE_DIRECTORY)))
|
|
{
|
|
// BUG BUG BUG We probably want to make sure that the old path gets deleted on other machines....
|
|
// We'll use the system path
|
|
// BUG BUG BUG BUG BUG We are *NOT* recording this default location in the registry. Thus, on another
|
|
// machine, the user might still be able to use the set cache location.
|
|
memcpy(pszPath, m_szSharedPath, cbS);
|
|
LoadString(GlobalDllHandle, g_dwCachePathResourceID[m_dwWorking], pszPath+cbS, MAX_PATH - cbS);
|
|
SetPerUserStatus(FALSE);
|
|
}
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
public:
|
|
IE5_REGISTRYSET()
|
|
{
|
|
m_fInitialised = FALSE;
|
|
}
|
|
|
|
virtual DWORD InitialiseKeys(BOOL& fProfilesCapable)
|
|
{
|
|
if (m_fInitialised)
|
|
{
|
|
fProfilesCapable = m_fProfiles;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
|
|
fProfilesCapable = TRUE;
|
|
#ifndef UNIX
|
|
cbS = GetWindowsDirectory(m_szSharedPath, sizeof(m_szSharedPath));
|
|
#else
|
|
/* On Unix, GetWindowsDirectory points to <install dir>/common
|
|
* And, we don't want to put the cache here.
|
|
*/
|
|
lstrcpy(m_szSharedPath, UNIX_SHARED_CACHE_PATH);
|
|
cbS = lstrlen(m_szSharedPath);
|
|
#endif /* UNIX */
|
|
if (!cbS || (cbS>sizeof(m_szSharedPath)))
|
|
return ERROR_PATH_NOT_FOUND;
|
|
|
|
AppendSlashIfNecessary(m_szSharedPath, &cbS);
|
|
|
|
cbP = 0;
|
|
// We think that profiles are enabled, so we want to get some info before
|
|
// proceeding. If any of this fails, though, we'll default to no profiles.
|
|
switch (GlobalPlatformType)
|
|
{
|
|
#ifndef UNIX
|
|
case PLATFORM_TYPE_WIN95:
|
|
{
|
|
REGISTRY_OBJ roProfilesEnabled(HKEY_LOCAL_MACHINE, PROFILES_ENABLED_VALUE);
|
|
DWORD dwProfilesEnabled = 0;
|
|
if ( (roProfilesEnabled.GetStatus() == ERROR_SUCCESS)
|
|
&&
|
|
((roProfilesEnabled.GetValue(PROFILES_ENABLED, &dwProfilesEnabled))==ERROR_SUCCESS)
|
|
&&
|
|
dwProfilesEnabled)
|
|
{
|
|
// Windows 95 sets the profiles path in the registry.
|
|
CHAR szProfilesRegValue[MAX_PATH];
|
|
memcpy(szProfilesRegValue, PROFILES_PATH_VALUE, sizeof(PROFILES_PATH_VALUE)-1);
|
|
cbP = sizeof(PROFILES_PATH_VALUE)-1;
|
|
AppendSlashIfNecessary(szProfilesRegValue, &cbP);
|
|
cbP = MAX_PATH-sizeof(PROFILES_PATH_VALUE);
|
|
if (GetUserName(szProfilesRegValue + sizeof(PROFILES_PATH_VALUE), &cbP))
|
|
{
|
|
cbP = MAX_PATH;
|
|
REGISTRY_OBJ roProfilesDirKey(HKEY_LOCAL_MACHINE, szProfilesRegValue);
|
|
|
|
if (!(((dwError = roProfilesDirKey.GetStatus()) != ERROR_SUCCESS)
|
|
||
|
|
((dwError = roProfilesDirKey.GetValue(PROFILES_PATH, (LPBYTE) m_szProfilePath,
|
|
&cbP)) != ERROR_SUCCESS)))
|
|
{
|
|
m_szProfilePath[cbP-1] = DIR_SEPARATOR_CHAR;
|
|
m_szProfilePath[cbP] = '\0';
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// Either
|
|
// (a) Couldn't get the profiles path from the registry.
|
|
// (b) Couldn't get the user name!
|
|
// Make the directory the windows directory
|
|
fProfilesCapable = FALSE;
|
|
break;
|
|
}
|
|
|
|
case PLATFORM_TYPE_WINNT:
|
|
// Windows NT sets the USERPROFILE environment
|
|
// string which contains the user's profile path
|
|
if (cbP = GetEnvironmentVariable("USERPROFILE", m_szProfilePath, MAX_PATH))
|
|
{
|
|
m_szProfilePath[cbP++] = DIR_SEPARATOR_CHAR;
|
|
m_szProfilePath[cbP] = '\0';
|
|
}
|
|
else
|
|
{
|
|
INET_ASSERT(FALSE);
|
|
// Getting the user profiles dir from the environment
|
|
// failed. Set the profiles directory to default.
|
|
memcpy(m_szProfilePath, m_szSharedPath, cbS);
|
|
memcpy(m_szProfilePath + cbS, DEFAULT_PROFILES_DIRECTORY, sizeof(DEFAULT_PROFILES_DIRECTORY));
|
|
cbP = cbS + sizeof(DEFAULT_PROFILES_DIRECTORY) - 1;
|
|
|
|
DWORD cbUser = MAX_PATH - cbP;;
|
|
GetUserName(m_szProfilePath + cbP, &cbUser);
|
|
cbP += cbUser;
|
|
}
|
|
break;
|
|
|
|
#else /* UNIX */
|
|
case PLATFORM_TYPE_UNIX:
|
|
lstrcpy(m_szProfilePath,TEXT("%USERPROFILE%"));
|
|
lstrcat(m_szProfilePath,DIR_SEPARATOR_STRING);
|
|
cbP = lstrlen(m_szProfilePath);
|
|
break;
|
|
#endif /* UNIX */
|
|
|
|
default:
|
|
// This should never happen.
|
|
INET_ASSERT(FALSE);
|
|
}
|
|
|
|
if (dwError==ERROR_SUCCESS)
|
|
{
|
|
dwError = InitCommonKeys(fProfilesCapable, CACHE5_KEY);
|
|
}
|
|
return dwError;
|
|
}
|
|
|
|
DWORD SetWorkingContainer(DWORD dwWhich)
|
|
{
|
|
m_dwWorking = dwWhich;
|
|
m_fWorkingPerUser = DetermineKeyPlacing(dwWhich);
|
|
return m_roWorking.WorkWith((m_fWorkingPerUser ? &m_roHKCUCache : &m_roHKLMCache), g_szSubKey[dwWhich], CREATE_KEY_IF_NOT_EXISTS);
|
|
}
|
|
|
|
VOID AttemptToUseSharedCache(PTSTR pszPath, DWORD ckbLimit);
|
|
|
|
// Path --------------------------------------------------------------------------
|
|
virtual DWORD GetPath(PTSTR pszPath)
|
|
{
|
|
if ((S_OK==SHGetFolderPath(NULL, g_iContainerCSIDL[m_dwWorking] | CSIDL_FLAG_CREATE, NULL, 0, pszPath))
|
|
&& (*pszPath!='\0'))
|
|
{
|
|
DWORD dwErr = ValidatePath(pszPath);
|
|
if (dwErr==ERROR_SUCCESS)
|
|
{
|
|
DWORD ccPath = lstrlen(pszPath);
|
|
// We check the lengths of the strings only when we're moving the containers. No need to do the check every
|
|
// time (assume a valid path)
|
|
if (m_dwWorking!=COOKIE)
|
|
{
|
|
EnableCacheVu(pszPath, m_dwWorking);
|
|
}
|
|
AppendSlashIfNecessary(pszPath, &ccPath);
|
|
|
|
#ifdef UNIX
|
|
/* On Unix, it is possible that IE4 and IE5 co-exist on a user's
|
|
* installation. So, we need to keep the IE4 cookies which are
|
|
* different from the IE5 cookies. For IE5, we have the following
|
|
* configuration for the caches -
|
|
*
|
|
* cookies - %HOME%/.microsoft/ie5/Cookies
|
|
* content - %HOME%/.microsoft/ie5/TempInternetFiles/Content.IE5
|
|
* history - %HOME%/.microsoft/ie5/History/History.IE5
|
|
*/
|
|
CHAR szIE5Dir[] = "ie5/";
|
|
int index = ccPath-2; // skip the last slash
|
|
int lenIE5Dir = lstrlen(szIE5Dir);
|
|
|
|
while(index >= 0 && pszPath[index] != FILENAME_SEPARATOR)
|
|
index--;
|
|
|
|
index++;
|
|
memmove(&pszPath[index+lenIE5Dir],&pszPath[index],ccPath-index+2);
|
|
memcpy(&pszPath[index],szIE5Dir,lenIE5Dir);
|
|
ccPath += lenIE5Dir;
|
|
#endif /* UNIX */
|
|
|
|
memcpy(pszPath+ccPath, g_szVersionName[m_dwWorking], lstrlen(g_szVersionName[m_dwWorking])+1);
|
|
if (GlobalIdentity && (m_dwWorking!=CONTENT))
|
|
{
|
|
if (!GenerateStringWithOrdinal(NULL, GlobalIdentity, pszPath, MAX_PATH))
|
|
{
|
|
dwErr = ERROR_INTERNET_INTERNAL_ERROR;
|
|
}
|
|
}
|
|
}
|
|
return dwErr;
|
|
}
|
|
return ERROR_INTERNET_INTERNAL_ERROR;
|
|
}
|
|
|
|
virtual DWORD SetPath(PTSTR pszPath)
|
|
{
|
|
INET_ASSERT(m_roWorking.GetStatus()==ERROR_SUCCESS);
|
|
DWORD dwError;
|
|
|
|
/* Try to preserve the environment variables on Unix */
|
|
UNIX_NORMALIZE_PATH_ALWAYS(pszPath, TEXT("%USERPROFILE%"));
|
|
if (m_fProfiles)
|
|
{
|
|
CHAR szScratch[MAX_PATH];
|
|
CompressPath(pszPath, szScratch);
|
|
if ((dwError = m_roUserShellFolder.SetValue(g_szOldSubKey[m_dwWorking], szScratch, REG_EXPAND_SZ))==ERROR_SUCCESS)
|
|
{
|
|
#ifndef UNIX
|
|
DWORD dwType = REG_SZ;
|
|
dwError = m_roShellFolder.SetValue(g_szOldSubKey[m_dwWorking],pszPath, dwType);
|
|
#else
|
|
dwError = m_roShellFolder.SetValue(g_szOldSubKey[m_dwWorking],szScratch, REG_EXPAND_SZ);
|
|
#endif /* UNIX */
|
|
}
|
|
// Possible BUG: If we move from the profiled path to the shared path, we still record it as a peruseritem.
|
|
SetPerUserStatus(TRUE);
|
|
}
|
|
// Non-profiles-enabled machine
|
|
// On Win9x machines, with profiles disabled, we need to write the path to the
|
|
// HKEY_USERS/.default/blah blah/Explorer/User Shell Folders to ensure that SHGetFolderPath returns
|
|
// the proper value for other users.
|
|
else
|
|
{
|
|
REGISTRY_OBJ roProfilesLessPath(HKEY_USERS, PROFILELESS_USF_KEY);
|
|
dwError = roProfilesLessPath.GetStatus();
|
|
if (dwError==ERROR_SUCCESS)
|
|
{
|
|
if ((dwError = roProfilesLessPath.SetValue(g_szOldSubKey[m_dwWorking],pszPath, REG_EXPAND_SZ))==ERROR_SUCCESS)
|
|
{
|
|
#ifndef UNIX
|
|
DWORD dwType = REG_SZ;
|
|
#else
|
|
DWORD dwType = REG_EXPAND_SZ;
|
|
#endif /* UNIX */
|
|
dwError = m_roUserShellFolder.SetValue(g_szOldSubKey[m_dwWorking],pszPath, dwType);
|
|
}
|
|
}
|
|
// For IE4 compatibility, we might have to adjust the old cache location here, as well.
|
|
}
|
|
return dwError;
|
|
}
|
|
|
|
|
|
// Prefix ------------------------------------------------------------------------
|
|
virtual DWORD GetPrefix(LPSTR szPrefix)
|
|
{
|
|
DWORD dwError, cbKeyLen = MAX_PATH;
|
|
if ((dwError = m_roWorking.GetValue(CACHE_PREFIX_VALUE, (LPBYTE) szPrefix, &cbKeyLen))==ERROR_SUCCESS)
|
|
{
|
|
if (cbKeyLen > 0)
|
|
{
|
|
// Strip trailing whitespace.
|
|
cbKeyLen--;
|
|
StripTrailingWhiteSpace(szPrefix, &cbKeyLen);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If no prefix found in registry create via
|
|
// defaults and write back to registry.
|
|
strncpy(szPrefix, g_szCachePrefix[m_dwWorking], MAX_PATH);
|
|
SetPrefix(szPrefix);
|
|
dwError = ERROR_SUCCESS;
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
virtual DWORD SetPrefix(PTSTR pszPrefix)
|
|
{
|
|
INET_ASSERT(m_roWorking.GetStatus()==ERROR_SUCCESS);
|
|
return m_roWorking.SetValue(CACHE_PREFIX_VALUE, (pszPrefix) ? pszPrefix : g_szCachePrefix[m_dwWorking], REG_SZ);
|
|
}
|
|
|
|
// Limit -------------------------------------------------------------------------
|
|
virtual DWORD GetLimit(PTSTR pszCachePath, DWORD& cbLimit)
|
|
{
|
|
if ((m_roWorking.GetValue(CACHE_LIMIT_VALUE, &cbLimit)!=ERROR_SUCCESS) || (cbLimit < 512))
|
|
{
|
|
cbLimit = 0;
|
|
return SetLimit(pszCachePath, cbLimit);
|
|
}
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
virtual DWORD SetLimit(PTSTR pszCachePath, DWORD& cbLimit);
|
|
|
|
// Use IsFirstTime* to figure out if this is the first time for this install of wininet and for marking it so ------------
|
|
private:
|
|
BOOL IsFirstTimeFor(HKEY hKey)
|
|
{
|
|
DWORD cb = MAX_PATH;
|
|
CHAR szSigKey[MAX_PATH];
|
|
REGISTRY_OBJ roSig(hKey, CACHE5_KEY);
|
|
|
|
return roSig.GetValue(CACHE_SIGNATURE_VALUE, (LPBYTE) szSigKey, &cb)==ERROR_SUCCESS ?
|
|
strcmp(szSigKey, CACHE_SIGNATURE) : TRUE;
|
|
}
|
|
|
|
public:
|
|
BOOL IsFirstTimeForUser()
|
|
{
|
|
return IsFirstTimeFor((m_fProfiles ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE));
|
|
}
|
|
|
|
BOOL IsFirstTimeForMachine()
|
|
{
|
|
return IsFirstTimeFor(HKEY_LOCAL_MACHINE);
|
|
}
|
|
|
|
VOID SetIfFirstTime()
|
|
{
|
|
DWORD cb = MAX_PATH;
|
|
CHAR szSigKey[MAX_PATH];
|
|
|
|
// On a profiles-not-enabled machine, store the signature in HKLM so we don't have to research for values
|
|
// On a profiles-enabled machine, store there to notify IE of previous installation of IE5.
|
|
REGISTRY_OBJ roSig(HKEY_LOCAL_MACHINE, CACHE5_KEY);
|
|
roSig.SetValue(CACHE_SIGNATURE_VALUE, CACHE_SIGNATURE, REG_SZ);
|
|
|
|
// On profiles-enabled machines, we store a signature in HKCU so that we don't have to do
|
|
// much hunting for registry values
|
|
if (m_fProfiles)
|
|
{
|
|
REGISTRY_OBJ roSig(HKEY_CURRENT_USER, CACHE5_KEY);
|
|
roSig.SetValue(CACHE_SIGNATURE_VALUE, CACHE_SIGNATURE, REG_SZ);
|
|
}
|
|
}
|
|
|
|
// PerUserItem ---------------------------------------------------------------------
|
|
virtual VOID SetPerUserStatus(BOOL fState)
|
|
{
|
|
DWORD flState = fState;
|
|
if (m_fProfiles && fState!=m_fWorkingPerUser)
|
|
{
|
|
REGISTRY_OBJ roTemp(&m_roHKCUCache, g_szSubKey[m_dwWorking], CREATE_KEY_IF_NOT_EXISTS);
|
|
if (roTemp.GetStatus()==ERROR_SUCCESS)
|
|
{
|
|
roTemp.SetValue(PER_USER_KEY, &flState);
|
|
m_roWorking.WorkWith((fState ? &m_roHKCUCache
|
|
: &m_roHKLMCache), g_szSubKey[m_dwWorking], CREATE_KEY_IF_NOT_EXISTS);
|
|
m_fWorkingPerUser = fState;
|
|
}
|
|
}
|
|
}
|
|
|
|
virtual DWORD GetPerUserStatus()
|
|
{
|
|
return m_fWorkingPerUser;
|
|
}
|
|
|
|
DWORD UpdateContentPath(PSTR pszNewPath)
|
|
{
|
|
TCHAR szOldPath[MAX_PATH];
|
|
DWORD dwError;
|
|
|
|
dwError = ERROR_SUCCESS;
|
|
|
|
if ((dwError=SetWorkingContainer(CONTENT))==ERROR_SUCCESS)
|
|
{
|
|
INTERNET_CACHE_CONFIG_INFOA icci;
|
|
icci.dwContainer = CONTENT;
|
|
GetUrlCacheConfigInfoA(&icci, NULL, CACHE_CONFIG_DISK_CACHE_PATHS_FC);
|
|
strncpy(szOldPath, icci.CachePath, ARRAY_ELEMENTS(szOldPath));
|
|
|
|
if (((dwError=MoveCachedFiles(szOldPath, pszNewPath))==ERROR_SUCCESS)
|
|
&&
|
|
((dwError=SetPath(pszNewPath))==ERROR_SUCCESS))
|
|
{
|
|
EnableCacheVu(pszNewPath);
|
|
|
|
// Right now, we're adding entries so that once we restart, we'll delete any
|
|
// stray files.
|
|
|
|
// BUT, there's a case that Move will be interrupted; in that case, we ought
|
|
// to finish the move on start up -- pop up a dialog notifying user of such
|
|
// and then delete.
|
|
// Also, if the Move's interrupted, then this info never will get written. OTOH,
|
|
// we can argue that the user can just move from the old location to the new.
|
|
|
|
CHAR szRunOnce [2 * MAX_PATH];
|
|
CHAR szSystemPath [MAX_PATH];
|
|
|
|
// Add a RunOnce entry to be run on reboot.
|
|
REGISTRY_OBJ roRunOnce((m_fWorkingPerUser ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE), RUN_ONCE_KEY, CREATE_KEY_IF_NOT_EXISTS);
|
|
if ((dwError=roRunOnce.GetStatus())!=ERROR_SUCCESS)
|
|
return dwError;
|
|
|
|
// create RunOnce string in the form:
|
|
// "rundll32.exe <system dir>\wininet.dll,RunOnceUrlCache C:\Windows\NewCacheLocation"
|
|
if (!GetSystemDirectory(szSystemPath, MAX_PATH))
|
|
return ERROR_INTERNAL_ERROR;
|
|
|
|
DisableCacheVu(szOldPath);
|
|
// Get rid of content.ie5.
|
|
PathRemoveBackslash(szOldPath);
|
|
PathRemoveFileSpec(szOldPath);
|
|
DisableCacheVu(szOldPath);
|
|
GetShortPathName(szOldPath, szOldPath, ARRAY_ELEMENTS(szOldPath));
|
|
wnsprintf(szRunOnce, sizeof(szRunOnce),
|
|
"rundll32.exe %s\\wininet.dll,RunOnceUrlCache %s",
|
|
szSystemPath, szOldPath);
|
|
|
|
// Set the RunOnce command in registry for wininet.
|
|
roRunOnce.SetValue(TEXT("MovingCacheA Wininet Settings"), (LPSTR)szRunOnce, REG_SZ);
|
|
}
|
|
}
|
|
return dwError;
|
|
}
|
|
};
|
|
|
|
#define m_roPaths m_roShellFolder
|
|
#define m_roSpecialPaths m_roHKCUCache
|
|
|
|
class IE3_REGISTRYSET : public IE5_REGISTRYSET
|
|
{
|
|
// Registry keys shipped with IE 3:
|
|
//
|
|
// Software\Microsoft\Windows\CurrentVersion\Internet Settings\Cache\Paths
|
|
//
|
|
// Software\Microsoft\Windows\CurrentVersion\Internet Settings\Cache\Paths\path1
|
|
// \path2
|
|
// \path3
|
|
// \path4
|
|
//
|
|
// Software\Microsoft\Windows\CurrentVersion\Internet Settings\Cache\Special Paths
|
|
//
|
|
// Software\Microsoft\Windows\CurrentVersion\Internet Settings\Cache\Special Paths\Cookies
|
|
// \History
|
|
//
|
|
// Software\Microsoft\Windows\CurrentVersion\Internet Settings\Cache\Url History
|
|
|
|
private:
|
|
REGISTRY_OBJ m_roPath[DEF_NUM_PATHS];
|
|
|
|
public:
|
|
// Initialise the IE3 keys that we might work with.
|
|
|
|
DWORD InitialiseKeys()
|
|
{
|
|
DWORD dwError, i;
|
|
TCHAR szScratch[MAX_PATH];
|
|
TCHAR pszBase[MAX_PATH];
|
|
DWORD dwBaseLen;
|
|
|
|
if (m_fInitialised)
|
|
{
|
|
return ERROR_SUCCESS;
|
|
}
|
|
m_roHKLMCache.WorkWith(HKEY_LOCAL_MACHINE, OLD_CACHE_KEY, CREATE_KEY_IF_NOT_EXISTS);
|
|
if ((dwError=m_roHKLMCache.GetStatus())!=ERROR_SUCCESS)
|
|
goto exit;
|
|
|
|
m_roPaths.WorkWith(&m_roHKLMCache, CACHE_PATHS_KEY, CREATE_KEY_IF_NOT_EXISTS);
|
|
if ((dwError=m_roPaths.GetStatus())!=ERROR_SUCCESS)
|
|
goto exit;
|
|
|
|
memcpy(pszBase, OLD_CACHE_PATH, sizeof(OLD_CACHE_PATH));
|
|
dwBaseLen = sizeof(OLD_CACHE_PATH) - 1;
|
|
for (i = 0; i < DEF_NUM_PATHS; i++)
|
|
{
|
|
pszBase[dwBaseLen-1] = (TCHAR)('1' + i);
|
|
m_roPath[i].WorkWith(&m_roPaths, pszBase, CREATE_KEY_IF_NOT_EXISTS);
|
|
if ((dwError=m_roPath[i].GetStatus())!=ERROR_SUCCESS)
|
|
goto exit;
|
|
}
|
|
|
|
m_roSpecialPaths.WorkWith(&m_roHKLMCache, CACHE_SPECIAL_PATHS_KEY);
|
|
m_fInitialised = TRUE;
|
|
exit:
|
|
return dwError;
|
|
}
|
|
|
|
BOOL GetContentDetails(LPSTR szPath, DWORD& cbLimit)
|
|
{
|
|
DWORD cbKey = MAX_PATH;
|
|
if (m_roPaths.GetValue(CACHE_DIRECTORY_VALUE, (LPBYTE)szPath, &cbKey)!=ERROR_SUCCESS)
|
|
return FALSE;
|
|
|
|
cbLimit = 0;
|
|
for (int i=0; i<DEF_NUM_PATHS; i++)
|
|
{
|
|
if (m_roPath[i].GetValue(CACHE_LIMIT_VALUE, &cbKey)!=ERROR_SUCCESS)
|
|
{
|
|
cbLimit = GetDefaultCacheQuota(szPath, NEW_CONTENT_QUOTA_DEFAULT_DISK_FRACTION);
|
|
break;
|
|
}
|
|
cbLimit += cbKey;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD SetPath(PTSTR pszPath)
|
|
{
|
|
DWORD i, nPaths, dwError;
|
|
DWORD cb = strlen((LPSTR)pszPath);
|
|
TCHAR szBase[MAX_PATH];
|
|
#ifndef UNIX
|
|
DWORD dwType = REG_SZ;
|
|
#else
|
|
DWORD dwType = REG_EXPAND_SZ;
|
|
#endif /* UNIX */
|
|
|
|
/* On Unix, try to preserve the Environment variables if possible */
|
|
UNIX_NORMALIZE_PATH_ALWAYS(pszPath, TEXT("%USERPROFILE%"));
|
|
|
|
|
|
// Cache content path.
|
|
if ((dwError = m_roPaths.SetValue(CACHE_DIRECTORY_VALUE, (LPSTR)pszPath, dwType)) != ERROR_SUCCESS)
|
|
goto exit;
|
|
|
|
// Number of subdirectories (optional).
|
|
nPaths = DEF_NUM_PATHS;
|
|
if ((dwError = m_roPaths.SetValue(CACHE_PATHS_KEY, &nPaths)) != ERROR_SUCCESS)
|
|
goto exit;
|
|
|
|
memcpy(szBase, pszPath, cb);
|
|
memcpy(szBase + cb, OLD_CACHE_SUBKEY, sizeof(OLD_CACHE_SUBKEY));
|
|
cb += sizeof(OLD_CACHE_SUBKEY) - 2;
|
|
// Subdirectories' paths and limits from CONTENT.
|
|
for (i = 0; i < DEF_NUM_PATHS; i++)
|
|
{
|
|
szBase[cb] = (TCHAR)('1' + i);
|
|
if ((dwError = m_roPath[i].SetValue(CACHE_PATH_VALUE, szBase, REG_SZ)) != ERROR_SUCCESS)
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
INET_ASSERT(dwError == ERROR_SUCCESS);
|
|
return dwError;
|
|
}
|
|
|
|
DWORD SetLimit(DWORD dwLimit)
|
|
{
|
|
DWORD i, nPaths, dwError;
|
|
|
|
for (i = 0; i < DEF_NUM_PATHS; i++)
|
|
{
|
|
DWORD cbCacheLimitPerSubCache = (DWORD) (dwLimit/ DEF_NUM_PATHS);
|
|
if ((dwError = m_roPath[i].SetValue(CACHE_LIMIT_VALUE, &cbCacheLimitPerSubCache)) != ERROR_SUCCESS)
|
|
goto exit;
|
|
}
|
|
exit:
|
|
INET_ASSERT(dwError == ERROR_SUCCESS);
|
|
return dwError;
|
|
}
|
|
|
|
// Restore key IE3 values. *snicker* --------------------------------------------
|
|
VOID FixLegacySettings(PTSTR pszPath, DWORD cbLimit)
|
|
{
|
|
if (InitialiseKeys()==ERROR_SUCCESS)
|
|
{
|
|
SetPath(pszPath);
|
|
SetLimit(cbLimit);
|
|
}
|
|
}
|
|
};
|
|
|
|
class IE4_REGISTRYSET : public IE5_REGISTRYSET
|
|
{
|
|
private:
|
|
BOOL DetermineKeyPlacing(DWORD dwWhich)
|
|
{
|
|
DWORD dwValue;
|
|
if (m_fProfiles && (dwWhich==CONTENT))
|
|
{
|
|
if (m_roHKLMCache.GetValue(PROFILES_ENABLED, &dwValue)==ERROR_SUCCESS)
|
|
{
|
|
return dwValue;
|
|
}
|
|
|
|
#ifndef UNIX
|
|
if (GlobalPlatformType == PLATFORM_TYPE_WINNT)
|
|
#else
|
|
if (GlobalPlatformType == PLATFORM_TYPE_UNIX)
|
|
#endif /* !UNIX */
|
|
{
|
|
return m_fProfiles;
|
|
}
|
|
|
|
// On Win9x we have to go through the following contortions to decide whether or not the
|
|
// user is using a per-user cache or a shared cache.
|
|
|
|
TCHAR szPath[MAX_PATH];
|
|
DWORD cbPath = sizeof(szPath);
|
|
if (m_roShellFolder.GetValue(g_szOldSubKey[m_dwWorking],(LPBYTE)szPath, &cbPath)==ERROR_SUCCESS)
|
|
{
|
|
cbPath = sizeof(szPath);
|
|
return (m_roUserShellFolder.GetValue(g_szOldSubKey[m_dwWorking],(LPBYTE)szPath, &cbPath)==ERROR_SUCCESS);
|
|
}
|
|
}
|
|
return m_fProfiles;
|
|
}
|
|
|
|
public:
|
|
DWORD InitialiseKeys(BOOL& fProfiles)
|
|
{
|
|
if (m_fInitialised)
|
|
{
|
|
return ERROR_SUCCESS;
|
|
}
|
|
return InitCommonKeys(fProfiles, OLD_CACHE_KEY);
|
|
}
|
|
|
|
DWORD GetPath(PTSTR pszCachePath)
|
|
{
|
|
DWORD cbKeyLen = MAX_PATH;
|
|
LOG_UPGRADE_DATA("Getting IE4 cache location...\n");
|
|
|
|
DWORD dwError = m_fProfiles ? m_roShellFolder.GetValue(g_szOldSubKey[m_dwWorking],(LPBYTE)pszCachePath, &cbKeyLen)
|
|
: m_roWorking.GetValue(CACHE_PATH_VALUE, (LPBYTE)pszCachePath, &cbKeyLen);
|
|
#ifndef UNIX
|
|
if (m_fProfiles && (GlobalPlatformType == PLATFORM_TYPE_WINNT) && (dwError==ERROR_SUCCESS))
|
|
#else
|
|
if (m_fProfiles && (GlobalPlatformType == PLATFORM_TYPE_UNIX) && (dwError==ERROR_SUCCESS))
|
|
#endif /* UNIX */
|
|
{
|
|
LOG_UPGRADE_DATA("Correcting IE4 cache location...\n");
|
|
LOG_UPGRADE_DATA(pszCachePath);
|
|
LOG_UPGRADE_DATA("\n");
|
|
TCHAR szPath[MAX_PATH];
|
|
DWORD cbPath = ARRAY_ELEMENTS(szPath);
|
|
if (m_roUserShellFolder.GetValue(g_szOldSubKey[m_dwWorking],(LPBYTE)szPath, &cbPath)!=ERROR_SUCCESS)
|
|
{
|
|
CompressPath(pszCachePath, szPath);
|
|
dwError = m_roUserShellFolder.SetValue(g_szOldSubKey[m_dwWorking], szPath, REG_EXPAND_SZ);
|
|
}
|
|
}
|
|
return dwError;
|
|
}
|
|
|
|
BOOL WasIE4Present(BOOL& fProfilesCapable)
|
|
{
|
|
DWORD cb = MAX_PATH;
|
|
CHAR szSigKey[MAX_PATH];
|
|
REGISTRY_OBJ roSig((fProfilesCapable ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE), OLD_CACHE_KEY);
|
|
|
|
return (roSig.GetValue(CACHE_SIGNATURE_VALUE, (LPBYTE) szSigKey, &cb)==ERROR_SUCCESS);
|
|
}
|
|
|
|
DWORD SetLimit(PTSTR pszCachePath, DWORD& cbLimit)
|
|
{
|
|
INET_ASSERT(m_roWorking.GetStatus()==ERROR_SUCCESS);
|
|
// If no limit found in registry create via
|
|
// defaults and write back to registry.
|
|
// Cache limit - for the content cache we calculate the cache limit
|
|
// as being max(DEF_CACHE_LIMIT, 1/32 of the disk size) All others caches
|
|
// are set to DEF_CACHE_LIMIT.
|
|
if (cbLimit==0)
|
|
{
|
|
cbLimit = (m_dwWorking==CONTENT)
|
|
? GetDefaultCacheQuota(pszCachePath, NEW_CONTENT_QUOTA_DEFAULT_DISK_FRACTION)
|
|
: DEF_CACHE_LIMIT;
|
|
}
|
|
|
|
// Dumb hack for back compat. *sigh*
|
|
if (m_dwWorking==CONTENT)
|
|
{
|
|
REGISTRY_OBJ roLimit(&m_roHKLMCache, g_szSubKey[CONTENT]);
|
|
if (roLimit.GetStatus()==ERROR_SUCCESS)
|
|
{
|
|
roLimit.SetValue(CACHE_LIMIT_VALUE, &cbLimit);
|
|
}
|
|
}
|
|
return m_roWorking.SetValue(CACHE_LIMIT_VALUE, &cbLimit);
|
|
}
|
|
};
|
|
|
|
|
|
DWORD IE5_REGISTRYSET::SetLimit(PTSTR pszCachePath, DWORD& cbLimit)
|
|
{
|
|
INET_ASSERT(m_roWorking.GetStatus()==ERROR_SUCCESS);
|
|
// If no limit found in registry create via
|
|
// defaults and write back to registry.
|
|
// Cache limit - for the content cache we calculate the cache limit
|
|
// as being max(DEF_CACHE_LIMIT, 1/32 of the disk size) All others caches
|
|
// are set to DEF_CACHE_LIMIT.
|
|
if (cbLimit==0)
|
|
{
|
|
cbLimit = (m_dwWorking==CONTENT)
|
|
? GetDefaultCacheQuota(pszCachePath, NEW_CONTENT_QUOTA_DEFAULT_DISK_FRACTION)
|
|
: DEF_CACHE_LIMIT;
|
|
}
|
|
DWORD dwError = m_roWorking.SetValue(CACHE_LIMIT_VALUE, &cbLimit);
|
|
if (dwError==ERROR_SUCCESS)
|
|
{
|
|
// Hack so that apps that read the cache quota from the registry are
|
|
// still able to do so.
|
|
IE4_REGISTRYSET ie4;
|
|
dwError = ie4.InitialiseKeys(m_fProfiles);
|
|
if (dwError==ERROR_SUCCESS)
|
|
{
|
|
ie4.SetWorkingContainer(m_dwWorking);
|
|
ie4.SetLimit(pszCachePath, cbLimit);
|
|
}
|
|
}
|
|
return dwError;
|
|
}
|
|
|
|
|
|
#define IsFieldSet(fc, bitFlag) (((fc) & (bitFlag)) != 0)
|
|
|
|
#define FAILSAFE_TIMEOUT (60000)
|
|
#define UNMAP_TIME (120000)
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// The following functions deal with keeping the cache containers all up and ready
|
|
|
|
// -- ConfigureCache() --------------------------------------------------------
|
|
// Get the cache info from registry and try to init.
|
|
|
|
// In general, GetCacheConfigInfo should only rarely fail -- mostly whenever HKCU
|
|
// is expected but not available. In that case, we use the system root cache.
|
|
// If _that_ fails, we panic.
|
|
|
|
DWORD CConMgr::ConfigureCache()
|
|
{
|
|
for (DWORD iter = 0; ; iter++)
|
|
{
|
|
DWORD dwError;
|
|
switch (iter)
|
|
{
|
|
case 0:
|
|
dwError = GetCacheConfigInfo();
|
|
break;
|
|
|
|
case 1:
|
|
dwError = GetSysRootCacheConfigInfo();
|
|
break;
|
|
|
|
default:
|
|
INET_ASSERT(FALSE);
|
|
return dwError;
|
|
}
|
|
|
|
if (dwError==ERROR_SUCCESS && (dwError=InitFixedContainers())==ERROR_SUCCESS)
|
|
break;
|
|
|
|
// If InitFixedContainers has failed, it is possible that the container list
|
|
// (ConList) is not empty. Make sure it has no entries.
|
|
LOCK_CACHE();
|
|
if (ConList.Size() != 0)
|
|
ConList.Free();
|
|
UNLOCK_CACHE();
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
DWORD CConMgr::GetCacheConfigInfo
|
|
----------------------------------------------------------------------------*/
|
|
DWORD CConMgr::GetCacheConfigInfo()
|
|
{
|
|
DWORD dwError, i;
|
|
|
|
// Prepare and initialise a registry set for every version of IE available.
|
|
// IE5 must be initialised first because it determines whether profiles are
|
|
// enabled on this machine and set ConMgr's _fProfilesCapable for future
|
|
// reference. Then IE4 and IE3 can be called in whatever order.
|
|
IE5_REGISTRYSET ie5rs;
|
|
if ((dwError=ie5rs.InitialiseKeys(_fProfilesCapable))!=ERROR_SUCCESS)
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
#ifdef WININET6
|
|
GlobalCacheHKey = (_fProfilesCapable ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE);
|
|
#endif
|
|
|
|
// Look for a signature to indicate that this cache has been placed before.
|
|
if (ie5rs.IsFirstTimeForUser())
|
|
{
|
|
LOG_UPGRADE_DATA("Install 1st time for user\n");
|
|
DiscoverRegistrySettings(&ie5rs);
|
|
} else {
|
|
// If the user is roaming across machines that include IE4,
|
|
// then safeguard against IE4 writing REG_SZ values that
|
|
// be REG_EXPAND_SZ.
|
|
CheckCacheLocationConsistency();
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------------
|
|
// Get the container paths, prefixes (if any) and default limit values.
|
|
for (i = CONTENT; i < NCONTAINERS; i++)
|
|
{
|
|
CHAR szCachePath[MAX_PATH];
|
|
CHAR szCachePrefix[MAX_PATH];
|
|
DWORD cbCacheLimit;
|
|
BOOL fPerUser;
|
|
// This should only rarely fail.
|
|
|
|
if ((dwError=ie5rs.SetWorkingContainer(i))!=ERROR_SUCCESS)
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
fPerUser = ie5rs.GetPerUserStatus();
|
|
dwError = ie5rs.GetPath(szCachePath);
|
|
LOG_UPGRADE_DATA("GetCacheConfigInfo/ie5rs.GetPath for user: ");
|
|
LOG_UPGRADE_DATA(szCachePath);
|
|
LOG_UPGRADE_DATA("\n");
|
|
|
|
if (dwError==ERROR_SUCCESS)
|
|
{
|
|
ie5rs.GetPrefix(szCachePrefix);
|
|
ie5rs.GetLimit(szCachePath, cbCacheLimit);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Got info, now create the container --------------------------------------
|
|
_coContainer[i] = new URL_CONTAINER(g_szSubKey[i],
|
|
szCachePath,
|
|
szCachePrefix,
|
|
(LONGLONG)cbCacheLimit*1024,
|
|
0);
|
|
|
|
if (_coContainer[i])
|
|
{
|
|
dwError = _coContainer[i]->GetStatus();
|
|
if (dwError!=ERROR_SUCCESS)
|
|
{
|
|
delete _coContainer[i];
|
|
break;
|
|
}
|
|
ConList.Add(_coContainer[i]);
|
|
_coContainer[i]->SetPerUserItem(fPerUser);
|
|
}
|
|
else
|
|
{
|
|
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
// Maintain values for backwards compatibility
|
|
if (i==CONTENT)
|
|
{
|
|
// If repairing IE3's settings fails, well, who cares? IE5 is still going.
|
|
IE3_REGISTRYSET ie3rs;
|
|
ie3rs.FixLegacySettings(szCachePath, cbCacheLimit);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return dwError;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
DWORD CConMgr::GetSysRootCacheConfigInfo
|
|
----------------------------------------------------------------------------*/
|
|
DWORD CConMgr::GetSysRootCacheConfigInfo()
|
|
{
|
|
CHAR szParentPath[MAX_PATH];
|
|
DWORD cb = ARRAY_ELEMENTS(szParentPath);
|
|
|
|
#ifndef UNIX
|
|
{
|
|
// In case of failure to create containers in the regular location,
|
|
// we should put the cache in a user-specifiable location HKLM\* REG_EXPAND_SZ
|
|
// Otherwise in the temp directory
|
|
// Otherwise in the Windows directory
|
|
REGISTRY_OBJ roCache(HKEY_LOCAL_MACHINE, CACHE5_KEY);
|
|
BOOL fResult = FALSE;
|
|
if (roCache.GetStatus()==ERROR_SUCCESS)
|
|
{
|
|
TCHAR szTemp[MAX_PATH];
|
|
if (roCache.GetValue(TEXT("SystemCache"), (LPBYTE)szTemp, &cb)==ERROR_SUCCESS)
|
|
{
|
|
cb = ExpandEnvironmentStrings(szTemp,szParentPath,ARRAY_ELEMENTS(szParentPath)) - 1;
|
|
if (cb && (cb < ARRAY_ELEMENTS(szParentPath)))
|
|
{
|
|
fResult = TRUE;
|
|
}
|
|
}
|
|
}
|
|
if (!fResult)
|
|
{
|
|
cb = ExpandEnvironmentStrings(TEXT("%TEMP%"),szParentPath,ARRAY_ELEMENTS(szParentPath)) - 1;
|
|
if (!cb || (cb > ARRAY_ELEMENTS(szParentPath)))
|
|
{
|
|
cb = GetWindowsDirectory(szParentPath, ARRAY_ELEMENTS(szParentPath));
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
/* On Unix, GetWindowsDirectory will point to <install dir>/common
|
|
* and the cache should not be created here in any case
|
|
*/
|
|
lstrcpy(szParentPath,UNIX_SHARED_CACHE_PATH);
|
|
cb = lstrlen(szParentPath);
|
|
#endif /* UNIX */
|
|
if (!cb || (cb>sizeof(szParentPath)))
|
|
{
|
|
return ERROR_PATH_NOT_FOUND;
|
|
}
|
|
AppendSlashIfNecessary(szParentPath, &cb);
|
|
|
|
for (DWORD idx = CONTENT; idx < NCONTAINERS; idx++)
|
|
{
|
|
CHAR szCachePath[MAX_PATH];
|
|
CHAR szCachePrefix[MAX_PATH];
|
|
LONGLONG cbCacheLimit;
|
|
|
|
// Get cache paths out of dll resource and form absolute
|
|
// paths to top level cache directories.
|
|
memcpy(szCachePath, szParentPath, cb);
|
|
if (!LoadString(GlobalDllHandle, g_dwCachePathResourceID[idx], szCachePath + cb, MAX_PATH - cb))
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
DWORD ccPath = lstrlen(szCachePath);
|
|
AppendSlashIfNecessary(szCachePath, &ccPath);
|
|
memcpy(szCachePath+ccPath, g_szVersionName[idx], lstrlen(g_szVersionName[idx])+1);
|
|
|
|
// Cache prefix.
|
|
memcpy(szCachePrefix, g_szCachePrefix[idx], strlen(g_szCachePrefix[idx]) + 1);
|
|
|
|
// Cache limit - for the content cache we calculate the cache limit
|
|
// as being max(DEF_CACHE_LIMIT, 1/32 of the disk size) All others caches
|
|
// are set to DEF_CACHE_LIMIT.
|
|
if (idx == CONTENT)
|
|
{
|
|
|
|
REGISTRY_OBJ roCache(HKEY_LOCAL_MACHINE, CACHE5_KEY);
|
|
BOOL fResult = (roCache.GetStatus()==ERROR_SUCCESS);
|
|
if (fResult)
|
|
{
|
|
REGISTRY_OBJ roLimit(&roCache, CONTENT_PATH_KEY);
|
|
fResult = FALSE;
|
|
if (roLimit.GetStatus()==ERROR_SUCCESS)
|
|
{
|
|
DWORD cKBLimit;
|
|
if (roLimit.GetValue(CACHE_LIMIT_VALUE, &cKBLimit)==ERROR_SUCCESS)
|
|
{
|
|
cbCacheLimit = cKBLimit * (LONGLONG)1024;
|
|
fResult = TRUE;
|
|
}
|
|
}
|
|
}
|
|
if (!fResult)
|
|
{
|
|
cbCacheLimit =
|
|
(DWORDLONG)GetDefaultCacheQuota(szCachePath, NEW_CONTENT_QUOTA_DEFAULT_DISK_FRACTION)
|
|
* (DWORDLONG)1024;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Non-CONTENT cache; use default.
|
|
cbCacheLimit = DEF_CACHE_LIMIT * (LONGLONG)1024;
|
|
}
|
|
|
|
_coContainer[idx] = new URL_CONTAINER(g_szSubKey[idx], szCachePath, szCachePrefix, cbCacheLimit, 0);
|
|
|
|
if (_coContainer[idx])
|
|
{
|
|
DWORD dwError = _coContainer[idx]->GetStatus();
|
|
if (dwError!=ERROR_SUCCESS)
|
|
{
|
|
delete _coContainer[idx];
|
|
return dwError;
|
|
}
|
|
ConList.Add(_coContainer[idx]);
|
|
_coContainer[idx]->SetPerUserItem(FALSE);
|
|
}
|
|
else
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
|
|
_fUsingBackupContainers = TRUE;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
BOOL CConMgr::GetUrlCacheConfigInfo
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CConMgr::GetUrlCacheConfigInfo(LPCACHE_CONFIG_INFO lpCacheConfigInfo,
|
|
LPDWORD lpdwCacheConfigInfoBufferSize, DWORD dwFieldControl)
|
|
{
|
|
LOCK_CACHE();
|
|
|
|
BOOL fIE5Struct = (lpCacheConfigInfo->dwStructSize == sizeof(INTERNET_CACHE_CONFIG_INFO));
|
|
|
|
if(IsFieldSet( dwFieldControl, CACHE_CONFIG_SYNC_MODE_FC))
|
|
{
|
|
lpCacheConfigInfo->dwSyncMode = GlobalUrlCacheSyncMode;
|
|
}
|
|
|
|
if (IsFieldSet(dwFieldControl, CACHE_CONFIG_QUOTA_FC))
|
|
{
|
|
lpCacheConfigInfo->dwQuota = (DWORD) (_coContainer[lpCacheConfigInfo->dwContainer]->GetCacheLimit()/1024L);
|
|
}
|
|
|
|
if (fIE5Struct && IsFieldSet(dwFieldControl, CACHE_CONFIG_CONTENT_USAGE_FC))
|
|
{
|
|
lpCacheConfigInfo->dwNormalUsage = (DWORD) (_coContainer[lpCacheConfigInfo->dwContainer]->GetCacheSize()/1024L);
|
|
}
|
|
|
|
if (fIE5Struct && IsFieldSet(dwFieldControl, CACHE_CONFIG_STICKY_CONTENT_USAGE_FC) && (lpCacheConfigInfo->dwContainer==CONTENT))
|
|
{
|
|
lpCacheConfigInfo->dwExemptUsage = (DWORD) (_coContainer[CONTENT]->GetExemptUsage()/1024L);
|
|
}
|
|
|
|
lpCacheConfigInfo->fPerUser = IsFieldSet( dwFieldControl, CACHE_CONFIG_USER_MODE_FC)
|
|
? _coContainer[lpCacheConfigInfo->dwContainer]->IsPerUserItem()
|
|
: _coContent->IsPerUserItem();
|
|
|
|
if (IsFieldSet(dwFieldControl, CACHE_CONFIG_CONTENT_PATHS_FC))
|
|
{
|
|
lpCacheConfigInfo->dwContainer = CONTENT;
|
|
}
|
|
else if (IsFieldSet(dwFieldControl, CACHE_CONFIG_HISTORY_PATHS_FC))
|
|
{
|
|
lpCacheConfigInfo->dwContainer = HISTORY;
|
|
}
|
|
else if (IsFieldSet(dwFieldControl, CACHE_CONFIG_COOKIES_PATHS_FC))
|
|
{
|
|
lpCacheConfigInfo->dwContainer = COOKIE;
|
|
}
|
|
// These are the actual field codes that should be sent for cache paths.
|
|
// Note that the path returned *does not* contain subdirs (cache1..N).
|
|
if (lpCacheConfigInfo->dwContainer <= HISTORY)
|
|
{
|
|
memcpy(lpCacheConfigInfo->CachePath,
|
|
_coContainer[lpCacheConfigInfo->dwContainer]->GetCachePath(),
|
|
_coContainer[lpCacheConfigInfo->dwContainer]->GetCachePathLen() + 1);
|
|
lpCacheConfigInfo->dwQuota = (DWORD)
|
|
(_coContainer[lpCacheConfigInfo->dwContainer]->GetCacheLimit() / 1024);
|
|
|
|
lpCacheConfigInfo->dwNumCachePaths = (DWORD) 1;
|
|
}
|
|
|
|
UNLOCK_CACHE();
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
BOOL CConMgr::SetUrlCacheConfigInfo
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CConMgr::SetUrlCacheConfigInfo(LPCACHE_CONFIG_INFO pConfig,
|
|
DWORD dwFieldControl)
|
|
{
|
|
DWORD i, dwError = ERROR_SUCCESS;
|
|
|
|
UNIX_RETURN_ERR_IF_READONLY_CACHE(dwError);
|
|
|
|
LOCK_CACHE();
|
|
|
|
// Check FieldControl bits and set the values for set fields
|
|
if( IsFieldSet( dwFieldControl, CACHE_CONFIG_SYNC_MODE_FC ))
|
|
{
|
|
|
|
INET_ASSERT(pConfig->dwSyncMode <= WININET_SYNC_MODE_AUTOMATIC);
|
|
|
|
InternetWriteRegistryDword(vszSyncMode, pConfig->dwSyncMode);
|
|
|
|
GlobalUrlCacheSyncMode = pConfig->dwSyncMode;
|
|
|
|
// set a new version and simultaneously
|
|
// increment copy for this process, so we don't
|
|
// read registry for this process
|
|
IncrementHeaderData(CACHE_HEADER_DATA_CURRENT_SETTINGS_VERSION,
|
|
&GlobalSettingsVersion);
|
|
}
|
|
|
|
if ( IsFieldSet( dwFieldControl, CACHE_CONFIG_DISK_CACHE_PATHS_FC ))
|
|
{
|
|
dwError = ERROR_INVALID_PARAMETER;
|
|
goto exit;
|
|
}
|
|
|
|
if ( IsFieldSet( dwFieldControl, CACHE_CONFIG_QUOTA_FC ) && pConfig->dwContainer==CONTENT)
|
|
{
|
|
DWORD cbSize = pConfig->dwQuota;
|
|
INET_ASSERT(cbSize);
|
|
|
|
if (!_fUsingBackupContainers)
|
|
{
|
|
IE5_REGISTRYSET ie5;
|
|
IE3_REGISTRYSET ie3;
|
|
|
|
if ((dwError=ie5.InitialiseKeys(_fProfilesCapable))!=ERROR_SUCCESS)
|
|
{
|
|
goto exit;
|
|
}
|
|
ie5.SetWorkingContainer(CONTENT);
|
|
TCHAR szTemp[MAX_PATH];
|
|
ie5.GetPath(szTemp);
|
|
ie5.SetLimit(szTemp, cbSize);
|
|
|
|
if (ie3.InitialiseKeys()==ERROR_SUCCESS)
|
|
{
|
|
ie3.FixLegacySettings(szTemp, cbSize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
REGISTRY_OBJ roCache(HKEY_LOCAL_MACHINE, CACHE5_KEY, CREATE_KEY_IF_NOT_EXISTS);
|
|
BOOL fResult = (roCache.GetStatus()==ERROR_SUCCESS);
|
|
if (fResult)
|
|
{
|
|
REGISTRY_OBJ roLimit(&roCache, CONTENT_PATH_KEY, CREATE_KEY_IF_NOT_EXISTS);
|
|
if (roLimit.GetStatus()==ERROR_SUCCESS)
|
|
{
|
|
roLimit.SetValue(CACHE_LIMIT_VALUE, &cbSize);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((((LONGLONG)cbSize * 1024) < _coContent->GetCacheSize()))
|
|
_coContent->CleanupUrls (DEFAULT_CLEANUP_FACTOR, 0);
|
|
_coContent->SetCacheLimit(cbSize* (LONGLONG)1024);
|
|
}
|
|
|
|
exit:
|
|
UNLOCK_CACHE();
|
|
BOOL fRet = (dwError==ERROR_SUCCESS);
|
|
if (!fRet)
|
|
{
|
|
SetLastError(dwError);
|
|
DEBUG_ERROR(INET, dwError);
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
DWORD CConMgr::SetContentPath
|
|
|
|
UpdateUrlCacheContentPath leads to this function.
|
|
This initiates the cache move. Should be called just before shutdown.
|
|
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CConMgr::SetContentPath(PTSTR pszNewPath)
|
|
{
|
|
IE5_REGISTRYSET ie5rs;
|
|
DWORD dwError;
|
|
BOOL fLock;
|
|
|
|
if (_coContent->LockContainer(&fLock)
|
|
&& (dwError=ie5rs.InitialiseKeys(_fProfilesCapable))==ERROR_SUCCESS)
|
|
{
|
|
dwError = ie5rs.UpdateContentPath(pszNewPath);
|
|
}
|
|
|
|
if (fLock)
|
|
{
|
|
_coContent->UnlockContainer();
|
|
}
|
|
|
|
if (dwError==ERROR_SUCCESS)
|
|
{
|
|
return TRUE;
|
|
}
|
|
SetLastError(dwError);
|
|
return FALSE;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
DWORD CConMgr::GetExtensibleCacheConfigInfo
|
|
----------------------------------------------------------------------------*/
|
|
DWORD CConMgr::GetExtensibleCacheConfigInfo(BOOL fAlways)
|
|
{
|
|
CHAR szCachePath[MAX_PATH];
|
|
CHAR szCachePrefix[MAX_PATH];
|
|
CHAR szPrefixMap[MAX_PATH];
|
|
CHAR szVolumeLabel[MAX_PATH];
|
|
CHAR szVolumeTitle[MAX_PATH];
|
|
|
|
LONGLONG cbCacheLimit;
|
|
|
|
HKEY hKey = (HKEY) INVALID_HANDLE_VALUE;
|
|
DWORD cbKeyLen, cbKBLimit, dwError = ERROR_SUCCESS;
|
|
CHAR szVendorKey[MAX_PATH];
|
|
|
|
URL_CONTAINER* pNewContainer;
|
|
URL_CONTAINER* co;
|
|
MUTEX_HOLDER mh;
|
|
|
|
DWORD idx;
|
|
DWORD idxPrefix;
|
|
DWORD dwNow;
|
|
DWORD dwOptions;
|
|
BOOL fModified;
|
|
BOOL fCDContainer;
|
|
|
|
REGISTRY_OBJ* pro = NULL;
|
|
|
|
LOCK_CACHE();
|
|
fModified = WasModified(TRUE);
|
|
|
|
hKey = _fProfilesCapable ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
|
|
|
|
// WasModified MUST come first, so that we update our cached count!
|
|
if (!fModified && !fAlways)
|
|
{
|
|
// Unmap every container that hasn't be referenced in UNMAP_TIME
|
|
dwNow = GetTickCountWrap();
|
|
if ((dwNow - _dwLastUnmap) > UNMAP_TIME)
|
|
{
|
|
for (idx = ConList.Size()-1; idx >= NCONTAINERS; idx--)
|
|
{
|
|
co = ConList.Get(idx);
|
|
if (co)
|
|
{
|
|
if (co->GetDeletePending() ||
|
|
((dwNow - co->GetLastReference()) > UNMAP_TIME))
|
|
{
|
|
co->TryToUnmap(1); // RefCount should be 1 == Us
|
|
}
|
|
co->Release(FALSE);
|
|
}
|
|
}
|
|
|
|
_dwLastUnmap = dwNow;
|
|
}
|
|
goto exit;
|
|
}
|
|
|
|
// Create registry object and entry.
|
|
pro = CreateExtensiRegObj(hKey);
|
|
if (!pro)
|
|
{
|
|
dwError = ERROR_ACCESS_DENIED;
|
|
goto exit;
|
|
}
|
|
|
|
{
|
|
REGISTRY_OBJ& roExtensibleCache = *pro;
|
|
for (idx = NCONTAINERS; idx < ConList.Size(); idx++)
|
|
{
|
|
URL_CONTAINER *co = ConList.Get(idx);
|
|
if (co)
|
|
{
|
|
co->Mark(FALSE);
|
|
co->Release(FALSE);
|
|
}
|
|
}
|
|
|
|
mh.Grab(_hMutexExtensible, FAILSAFE_TIMEOUT);
|
|
|
|
idx = NCONTAINERS;
|
|
// 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.
|
|
cbKeyLen = MAX_PATH;
|
|
DWORD dwRepair = TRUE;
|
|
CHAR szScratch[MAX_PATH];
|
|
|
|
roVendor.GetValue(CACHE_PATCH_VALUE, &dwRepair);
|
|
|
|
if (roVendor.GetValue(CACHE_PATH_VALUE, (LPBYTE) szScratch, &cbKeyLen) != ERROR_SUCCESS)
|
|
continue;
|
|
|
|
if (!*szScratch)
|
|
{
|
|
roExtensibleCache.DeleteKey(szVendorKey);
|
|
continue;
|
|
}
|
|
|
|
if (dwRepair)
|
|
{
|
|
CompressPath(szScratch, szCachePath);
|
|
cbKeyLen = lstrlen(szCachePath)+1;
|
|
roVendor.SetValue(CACHE_PATH_VALUE, szCachePath, REG_EXPAND_SZ);
|
|
dwRepair = FALSE;
|
|
roVendor.SetValue(CACHE_PATCH_VALUE, &dwRepair);
|
|
}
|
|
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;
|
|
|
|
// Limit.
|
|
if (roVendor.GetValue(CACHE_LIMIT_VALUE, &cbKBLimit) != ERROR_SUCCESS)
|
|
continue;
|
|
|
|
// Options.
|
|
if (roVendor.GetValue(CACHE_OPTIONS_VALUE, &dwOptions) != ERROR_SUCCESS)
|
|
continue;
|
|
|
|
if (dwOptions & INTERNET_CACHE_CONTAINER_MAP_ENABLED)
|
|
{
|
|
fCDContainer = TRUE;
|
|
|
|
// PrefixMap
|
|
cbKeyLen = MAX_PATH;
|
|
if ((roVendor.GetValue(CACHE_PREFIX_MAP_VALUE, (LPBYTE) szPrefixMap, &cbKeyLen) != ERROR_SUCCESS)
|
|
|| (*szPrefixMap == '\0'))
|
|
continue;
|
|
|
|
// Volume label.
|
|
cbKeyLen = MAX_PATH;
|
|
if ((roVendor.GetValue(CACHE_VOLUME_LABLE_VALUE, (LPBYTE) szVolumeLabel, &cbKeyLen) != ERROR_SUCCESS)
|
|
|| (*szVolumeLabel == '\0'))
|
|
continue;
|
|
|
|
// Volume title.
|
|
cbKeyLen = MAX_PATH;
|
|
if ((roVendor.GetValue(CACHE_VOLUME_TITLE_VALUE, (LPBYTE) szVolumeTitle, &cbKeyLen) != ERROR_SUCCESS)
|
|
|| (*szVolumeTitle == '\0'))
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
fCDContainer = FALSE;
|
|
*szPrefixMap = '\0';
|
|
dwOptions &= ~INTERNET_CACHE_CONTAINER_PREFIXMAP;
|
|
}
|
|
|
|
cbCacheLimit = ((LONGLONG) cbKBLimit) * 1024;
|
|
|
|
idxPrefix = FindExtensibleContainer(szVendorKey);
|
|
if (idxPrefix != NOT_AN_INDEX)
|
|
{
|
|
co = ConList.Get(idxPrefix);
|
|
|
|
if (co)
|
|
{
|
|
// what if the container has been added
|
|
// with the same name but a different path, prefix, or options!
|
|
if (stricmp(co->GetCachePath(), szCachePath) ||
|
|
stricmp(co->GetCachePrefix(), szCachePrefix) ||
|
|
co->GetOptions() != dwOptions)
|
|
{
|
|
idxPrefix = NOT_AN_INDEX;
|
|
}
|
|
else if (fCDContainer && stricmp(co->GetPrefixMap(), szPrefixMap))
|
|
{
|
|
idxPrefix = NOT_AN_INDEX;
|
|
}
|
|
else
|
|
{
|
|
co->Mark(TRUE);
|
|
}
|
|
co->Release(FALSE);
|
|
}
|
|
}
|
|
|
|
if (idxPrefix == NOT_AN_INDEX)
|
|
{
|
|
// Construct either a normal container, or a CD container.
|
|
if (!fCDContainer)
|
|
{
|
|
pNewContainer = new URL_CONTAINER(szVendorKey, szCachePath, szCachePrefix,
|
|
cbCacheLimit, dwOptions);
|
|
}
|
|
else
|
|
{
|
|
pNewContainer = new CInstCon(szVendorKey, szVolumeLabel, szVolumeTitle,
|
|
szCachePath, szCachePrefix, szPrefixMap,
|
|
cbCacheLimit, dwOptions);
|
|
}
|
|
if (pNewContainer)
|
|
{
|
|
dwError = pNewContainer->GetStatus();
|
|
if (dwError!=ERROR_SUCCESS)
|
|
{
|
|
delete pNewContainer;
|
|
pNewContainer = NULL;
|
|
}
|
|
else
|
|
{
|
|
pNewContainer->Mark(TRUE);
|
|
ConList.Add(pNewContainer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
idx++;
|
|
}
|
|
}
|
|
mh.Release();
|
|
|
|
// Mark every container that's no longer in the registry for pending delete
|
|
// Unmap every container that hasn't be referenced in UNMAP_TIME
|
|
dwNow = GetTickCountWrap();
|
|
|
|
idx = ConList.Size() - 1;
|
|
|
|
while (idx >= NCONTAINERS)
|
|
{
|
|
co = ConList.Get(idx);
|
|
if (co)
|
|
{
|
|
if (!co->GetMarked() && !co->GetDeleted())
|
|
{
|
|
co->SetDeletePending(TRUE);
|
|
}
|
|
if (co->GetDeletePending() ||
|
|
((dwNow - co->GetLastReference()) > UNMAP_TIME))
|
|
{
|
|
co->TryToUnmap(1); // RefCount should be 1 == Us, unless enumerator
|
|
// is still open
|
|
}
|
|
co->Release(FALSE);
|
|
}
|
|
idx--;
|
|
}
|
|
|
|
_dwLastUnmap = dwNow;
|
|
}
|
|
delete pro;
|
|
|
|
exit:
|
|
UNLOCK_CACHE();
|
|
return dwError;
|
|
}
|
|
|
|
|
|
//
|
|
// Mixed environment of IE4 and IE5 sharing a server causes HKCU keys to get resaved as REG_SZ incorrectly
|
|
// so we repair it here
|
|
VOID CheckCacheLocationConsistency()
|
|
{
|
|
// Read user shell folders (necessary only in HKCU) and write back as REG_EXPAND_SZ if necessary
|
|
REGISTRY_OBJ roUserShellFolders(HKEY_CURRENT_USER, USER_SHELL_FOLDER_KEY);
|
|
if (roUserShellFolders.GetStatus()!=ERROR_SUCCESS)
|
|
{
|
|
return;
|
|
}
|
|
for (int i=0; i<NCONTAINERS; i++)
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
DWORD cc = ARRAY_ELEMENTS(szPath);
|
|
DWORD ValueSize;
|
|
DWORD ValueType;
|
|
|
|
// speed things up a bit by checking if we don't need to do this
|
|
if (roUserShellFolders.GetValueSizeAndType(g_szOldSubKey[i], &ValueSize, &ValueType ) != SUCCESS
|
|
|| ValueType != REG_SZ)
|
|
{
|
|
continue;
|
|
}
|
|
if (roUserShellFolders.GetValue(g_szOldSubKey[i], (LPBYTE)szPath, &cc)!=ERROR_SUCCESS)
|
|
{
|
|
continue;
|
|
}
|
|
// First reconcile path to whatever it should be
|
|
// and rename the containers accordingly.
|
|
|
|
TCHAR szRealPath[MAX_PATH];
|
|
|
|
// Expand string
|
|
ExpandEnvironmentStrings(szPath, szRealPath, ARRAY_ELEMENTS(szRealPath));
|
|
|
|
// Contract string
|
|
if (!NormalisePath(szRealPath, TEXT("%USERPROFILE%"), szPath, sizeof(szPath)))
|
|
{
|
|
NormalisePath(szRealPath, TEXT("%SystemRoot%"), szPath, sizeof(szPath));
|
|
}
|
|
|
|
// Then write it back
|
|
roUserShellFolders.DeleteValue(g_szOldSubKey[i]);
|
|
roUserShellFolders.SetValue(g_szOldSubKey[i], szPath, REG_EXPAND_SZ);
|
|
}
|
|
}
|
|
|
|
|
|
VOID MakeCacheLocationsConsistent()
|
|
{
|
|
// Delete any 5.0 cache signatures from previous installs
|
|
REGISTRY_OBJ roHKCU(HKEY_CURRENT_USER, CACHE5_KEY);
|
|
if (roHKCU.GetStatus()==ERROR_SUCCESS)
|
|
{
|
|
roHKCU.DeleteValue(CACHE_SIGNATURE_VALUE);
|
|
}
|
|
|
|
// Read user shell folders (necessary only in HKCU) and write back as REG_EXPAND_SZ
|
|
REGISTRY_OBJ roUserShellFolders(HKEY_CURRENT_USER, USER_SHELL_FOLDER_KEY);
|
|
if (roUserShellFolders.GetStatus()!=ERROR_SUCCESS)
|
|
{
|
|
return;
|
|
}
|
|
roUserShellFolders.DeleteValue(TEXT("Content"));
|
|
|
|
for (int i=0; i<NCONTAINERS; i++)
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
DWORD cc = ARRAY_ELEMENTS(szPath);
|
|
if (roUserShellFolders.GetValue(g_szOldSubKey[i], (LPBYTE)szPath, &cc)!=ERROR_SUCCESS)
|
|
{
|
|
continue;
|
|
}
|
|
// First reconcile path to whatever it should be
|
|
// and rename the containers accordingly.
|
|
// i. Get rid of all the trailing content.ie5 (History.IE5)
|
|
// ii. Get rid of any trailing Temporary Internet Files (History)
|
|
// iii. Append Temporary Internet Files (History)
|
|
|
|
// We want to skip this for cookies, though.
|
|
|
|
// PROBLEM: When we have upgrade on top of 0901+, we started appending content.ie5
|
|
// internally. Thus, files start getting misplaced. How do I work around this?
|
|
|
|
// Idea: We append Content.ie5 to the USF path, and test for existence. If it's there,
|
|
// then we'll use that. (We won't bother with anymore detective work. Though we could also
|
|
// verify that the index dat there is newer than the index.dat in the parent directory.)
|
|
TCHAR szRealPath[MAX_PATH];
|
|
|
|
// Expand string
|
|
ExpandEnvironmentStrings(szPath, szRealPath, ARRAY_ELEMENTS(szRealPath));
|
|
DisableCacheVu(szRealPath);
|
|
|
|
if (i!=1)
|
|
{
|
|
}
|
|
|
|
// Contract string
|
|
if (!NormalisePath(szRealPath, TEXT("%USERPROFILE%"), szPath, sizeof(szPath)))
|
|
{
|
|
NormalisePath(szRealPath, TEXT("%SystemRoot%"), szPath, sizeof(szPath));
|
|
}
|
|
|
|
// Then write it back
|
|
roUserShellFolders.DeleteValue(g_szOldSubKey[i]);
|
|
roUserShellFolders.SetValue(g_szOldSubKey[i], szPath, REG_EXPAND_SZ);
|
|
|
|
// Then append Content.IE5 and move the files to this subdirectory
|
|
// Ideally, we should rename this to an intermediate folder,
|
|
// delete the old location (UNLESS THIS IS THE ROOT OR SYSTEM DIRECTORY),
|
|
// and then move intermediate folder to its new location
|
|
|
|
}
|
|
|
|
FlushShellFolderCache();
|
|
}
|
|
|
|
// External hooks -------------------------------------------------------------------------------------------------------
|
|
|
|
// -- RunOnceUrlCache -------------------------
|
|
// This code is called on reboot to clean up moving the cache.
|
|
// If the shutdown was successful, this will move only the few files that were open
|
|
// at that point; we assume that we'll move quickly enough to prevent collisions.
|
|
// The old index.dat is erased.
|
|
|
|
DWORD
|
|
WINAPI
|
|
RunOnceUrlCache( HWND hwnd, HINSTANCE hinst, PSTR pszCmd, int nCmdShow)
|
|
{
|
|
// This will clean up the move, especially important if the move was interrupted. (Not too likely.)
|
|
if (pszCmd && *pszCmd)
|
|
{
|
|
CFileMgr::DeleteCache(pszCmd);
|
|
}
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
DeleteIE3Cache( HWND hwnd, HINSTANCE hinst, PSTR lpszCmd, int nCmdShow)
|
|
{
|
|
IE3_REGISTRYSET ie3rs;
|
|
|
|
if (ie3rs.InitialiseKeys()==ERROR_SUCCESS)
|
|
{
|
|
TCHAR szTemp[MAX_PATH];
|
|
DWORD cbLimit;
|
|
|
|
// This fragment will look for a cache location, and test for its share-ability. If it is,
|
|
// we'll use the location; otherwise, we'll use our own shared location.
|
|
if (ie3rs.GetContentDetails(szTemp, cbLimit))
|
|
{
|
|
DWORD cb = lstrlen(szTemp);
|
|
AppendSlashIfNecessary(szTemp, &cb);
|
|
|
|
PTSTR psz = szTemp+cb-2;
|
|
while (*psz!='\\' && psz>szTemp)
|
|
{
|
|
psz--;
|
|
}
|
|
if ((psz>szTemp) && !StrCmpNI(psz+1, TEXT("content."), ARRAY_ELEMENTS("content.")-1))
|
|
{
|
|
*(psz+1) = TEXT('\0');
|
|
}
|
|
StrCatBuff(szTemp, TEXT("cache1"), MAX_PATH);
|
|
cb = lstrlen(szTemp) - 1;
|
|
|
|
for (int i=0; i<4; i++)
|
|
{
|
|
szTemp[cb] = TEXT('1')+i;
|
|
DeleteCachedFilesInDir(szTemp);
|
|
RemoveDirectory(szTemp);
|
|
}
|
|
}
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
// -- Externally available apis
|
|
|
|
URLCACHEAPI_(BOOL) SetUrlCacheConfigInfoA(
|
|
LPCACHE_CONFIG_INFO pConfig,
|
|
DWORD dwFieldControl
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sets the cache configuration parameters.
|
|
|
|
Arguments:
|
|
|
|
lpCacheConfigInfo - place holding cache configuration information to be set
|
|
|
|
dwFieldControl - items to get
|
|
|
|
Return Value:
|
|
|
|
Error Code
|
|
|
|
--*/
|
|
{
|
|
// Initialize globals
|
|
if (!InitGlobals())
|
|
{
|
|
SetLastError (ERROR_INTERNET_INTERNAL_ERROR);
|
|
return FALSE;
|
|
}
|
|
return GlobalUrlContainers->SetUrlCacheConfigInfo(pConfig,dwFieldControl);
|
|
}
|
|
|
|
URLCACHEAPI_(BOOL) GetUrlCacheConfigInfoA(
|
|
LPCACHE_CONFIG_INFO lpCacheConfigInfo,
|
|
IN OUT LPDWORD lpdwCacheConfigInfoBufferSize,
|
|
DWORD dwFieldControl
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function retrieves cache configuration values from globals
|
|
|
|
Arguments:
|
|
|
|
pConfig - pointer to a location where configuration information
|
|
is stored on a successful return
|
|
|
|
lpdwCacheConfigInfoBufferSize : pointer to a location where length of
|
|
the above buffer is passed in. On return, this contains the length
|
|
of the above buffer that is fulled in.
|
|
|
|
dwFieldControl - items to get
|
|
|
|
Return Value:
|
|
|
|
Error Code
|
|
|
|
--*/
|
|
{
|
|
ENTER_CACHE_API ((DBG_API, Bool, "GetUrlCacheConfigInfoA", "%#x, %#x, %#x",
|
|
lpCacheConfigInfo, lpdwCacheConfigInfoBufferSize, dwFieldControl ));
|
|
|
|
BOOL fError;
|
|
|
|
// Initialize globals
|
|
if (!InitGlobals())
|
|
{
|
|
SetLastError (ERROR_INTERNET_INTERNAL_ERROR);
|
|
DEBUG_ERROR(API, ERROR_INTERNET_INTERNAL_ERROR);
|
|
fError = FALSE;
|
|
}
|
|
else
|
|
{
|
|
fError = GlobalUrlContainers->GetUrlCacheConfigInfo(lpCacheConfigInfo,
|
|
lpdwCacheConfigInfoBufferSize, dwFieldControl);
|
|
}
|
|
|
|
DEBUG_LEAVE_API (fError);
|
|
return fError;
|
|
}
|
|
|
|
|
|
// declared in wininet\inc\urlcache.h
|
|
BOOL GetIE5ContentPath( LPSTR szPath)
|
|
{
|
|
BOOL retVal = FALSE;
|
|
|
|
IE5_REGISTRYSET ie5rs;
|
|
BOOL fProfilesCapable;
|
|
|
|
if( ie5rs.InitialiseKeys(fProfilesCapable) != ERROR_SUCCESS)
|
|
goto doneGetContentPath;
|
|
|
|
if( ie5rs.SetWorkingContainer(CONTENT) != ERROR_SUCCESS)
|
|
goto doneGetContentPath;
|
|
|
|
if( ie5rs.GetPath( szPath) != ERROR_SUCCESS)
|
|
goto doneGetContentPath;
|
|
|
|
retVal = TRUE;
|
|
|
|
doneGetContentPath:
|
|
return retVal;
|
|
}
|
|
|
|
// SHDOCVW needs to know whether profiles are enabled, to determine whether
|
|
// or not it needs to filter out user names. This function will help keep things simple.
|
|
// And minimise perf impact.
|
|
STDAPI_(BOOL) IsProfilesEnabled()
|
|
{
|
|
IE5_REGISTRYSET ie5rs;
|
|
BOOL fProfilesEnabled;
|
|
|
|
if (ie5rs.InitialiseKeys(fProfilesEnabled) != ERROR_SUCCESS)
|
|
{
|
|
fProfilesEnabled = FALSE;
|
|
}
|
|
return fProfilesEnabled;
|
|
}
|
|
|
|
BOOL CConMgr::DiscoverIE4Settings(IE5_REGISTRYSET* pie5rs)
|
|
{
|
|
IE4_REGISTRYSET ie4rs;
|
|
|
|
CHAR szTemp[MAX_PATH+1], szPrefix[MAX_PATH+1];
|
|
DWORD cbLimit, dwTemp;
|
|
BOOL fPerUser, fCaughtIE4;
|
|
|
|
// Try to find IE4 settings. If any paths are found, we will not look for IE3 settings
|
|
fCaughtIE4 = FALSE;
|
|
|
|
if (ie4rs.WasIE4Present(_fProfilesCapable))
|
|
{
|
|
if (ie4rs.InitialiseKeys(_fProfilesCapable)!=ERROR_SUCCESS)
|
|
{
|
|
LOG_UPGRADE_DATA("IE4 initialisation failed...\n");
|
|
return FALSE;
|
|
}
|
|
|
|
for (dwTemp=0;dwTemp < NCONTAINERS; dwTemp++)
|
|
{
|
|
ie4rs.SetWorkingContainer(dwTemp);
|
|
if (ie4rs.GetPath(szTemp)!=ERROR_SUCCESS)
|
|
{
|
|
continue;
|
|
}
|
|
LOG_UPGRADE_DATA("DIE4Settings: ");
|
|
LOG_UPGRADE_DATA(szTemp);
|
|
LOG_UPGRADE_DATA("\n");
|
|
DisableCacheVu(szTemp);
|
|
|
|
pie5rs->SetWorkingContainer(dwTemp);
|
|
|
|
// Because SHGetFolderPath uses shell folders to determine where the items are, we have to accomodate this
|
|
// on no-profiles machines.
|
|
if (!_fProfilesCapable)
|
|
{
|
|
pie5rs->SetPath(szTemp);
|
|
}
|
|
else if (dwTemp==CONTENT)
|
|
{
|
|
#ifndef UNIX
|
|
if (ie4rs.GetPerUserStatus() || GlobalPlatformVersion5)
|
|
#else
|
|
if (ie4rs.GetPerUserStatus() || GlobalPlatformType == PLATFORM_TYPE_UNIX)
|
|
#endif /* UNIX */
|
|
{
|
|
// If it's NT5, we want to go to a per-user, non-roaming location
|
|
// which is the NT5 default anyway
|
|
LOG_UPGRADE_DATA("DIE4Settings: If NT5, ignore shared cache. Else this isn't shared anyway.");
|
|
pie5rs->SetPerUserStatus(TRUE);
|
|
}
|
|
else
|
|
{
|
|
// Because IE4 locates a shared cache differently from IE5, we need to
|
|
// save the path and status.
|
|
LOG_UPGRADE_DATA("DIE4Settings: Will try to use shared cache");
|
|
pie5rs->AttemptToUseSharedCache(szTemp, 0);
|
|
}
|
|
}
|
|
|
|
fCaughtIE4 = TRUE;
|
|
|
|
// We don't need to check return values since we come up with
|
|
// reasonable values on our own.
|
|
ie4rs.GetLimit(szTemp, cbLimit);
|
|
pie5rs->SetLimit(szTemp, cbLimit);
|
|
|
|
ie4rs.GetPrefix(szPrefix);
|
|
pie5rs->SetPrefix(szPrefix);
|
|
}
|
|
}
|
|
if (!fCaughtIE4)
|
|
{
|
|
LOG_UPGRADE_DATA("No IE4 settings...\n");
|
|
}
|
|
else
|
|
{
|
|
FlushShellFolderCache();
|
|
}
|
|
return fCaughtIE4;
|
|
}
|
|
|
|
VOID CConMgr::DiscoverIE3Settings(IE5_REGISTRYSET* pie5rs)
|
|
{
|
|
IE3_REGISTRYSET ie3rs;
|
|
|
|
if (ie3rs.InitialiseKeys()!=ERROR_SUCCESS)
|
|
{
|
|
return;
|
|
}
|
|
|
|
TCHAR szTemp[MAX_PATH];
|
|
DWORD cbLimit;
|
|
|
|
// This fragment will look for a cache location, and test for its share-ability. If it is,
|
|
// we'll use the location; otherwise, we'll use our own shared location.
|
|
if (ie3rs.GetContentDetails(szTemp, cbLimit))
|
|
{
|
|
DeleteCachedFilesInDir(szTemp);
|
|
// No IE4. Steal IE3's settings? We only care about content cache.
|
|
// Is that a good idea? There's no UI for modifying the cookies/history path;
|
|
// if someone plumbs into the registry, do we want to support that? *sigh*
|
|
// BUG? We're moving the cache one level deeper. We probably want to be a
|
|
// bit more intelligent about this.
|
|
CleanPath(szTemp);
|
|
pie5rs->AttemptToUseSharedCache(szTemp, cbLimit);
|
|
}
|
|
|
|
// This fragment deletes the shared history. It should happen ONLY ONCE.
|
|
DWORD cbKeyLen = ARRAY_ELEMENTS(szTemp);
|
|
REGISTRY_OBJ roHist(HKEY_LOCAL_MACHINE, IE3_HISTORY_PATH_KEY);
|
|
if ((roHist.GetStatus()==ERROR_SUCCESS)
|
|
&&
|
|
(roHist.GetValue(NULL,(LPBYTE)szTemp, &cbKeyLen)==ERROR_SUCCESS))
|
|
{
|
|
REGISTRY_OBJ roUrlHist(HKEY_LOCAL_MACHINE, szTemp);
|
|
cbKeyLen = ARRAY_ELEMENTS(szTemp);
|
|
if ((roUrlHist.GetStatus()==ERROR_SUCCESS)
|
|
&&
|
|
(roUrlHist.GetValue(CACHE_DIRECTORY_VALUE, (LPBYTE)szTemp, &cbKeyLen)==ERROR_SUCCESS))
|
|
{
|
|
DeleteCachedFilesInDir(szTemp);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Logic for determining the location of the cache -------------------------------------------------------------
|
|
|
|
// PROFILES ENABLED --------------------------
|
|
// [on logon]
|
|
// If profiles are enabled, look in HKCU/Software/Microsoft/Windows/Internet Settings/5.0/Cache
|
|
// for a signature.
|
|
// If a signature is present, [carry on]
|
|
// Look in HKLM/Software/Microsoft/Windows/Internet Settings/5.0/Cache
|
|
// for a signature.
|
|
// If a signature is not present, jump to [over IE4 install]
|
|
// For history and cookies, the containers will be located in the profiles directory
|
|
// For content,
|
|
// if it's marked per user,
|
|
// and there isn't a shell folder/user shell folder value, construct and put it in
|
|
// otherwise feed the HKLM shared location into (user) shell folder.
|
|
// Insert signature and [carry on].
|
|
|
|
// [over IE4 install]
|
|
// If a signature is not present in HKCU/Software/Microsoft/Windows/Internet Settings/Cache,
|
|
// jump to [over IE3 install]
|
|
// Determine if the content cache is per-user or not.
|
|
|
|
// [over IE3 install]
|
|
// For history and cookies, the containers will be located in the profiles directory
|
|
// Examine HKLM/Software/Microsoft/Windows/Internet Settings/Cache/Paths
|
|
// If not present, go to [clean install]
|
|
// If the cache path is located in a user's profiles directory, ignore and [clean install]
|
|
// Otherwise, adopt the values and [carry on]
|
|
|
|
// [clean install]
|
|
// Set up history/cookies to be per user.
|
|
// Set up the content cache to be shared.
|
|
// Write in default values.
|
|
|
|
// PROFILES NOT ENABLED --------------------------
|
|
|
|
// * If profiles are _not_ enabled, we'll look in HKLM/Software/Microsoft/Windows/Internet Settings/5.0/Cache
|
|
// for a signature.
|
|
// If a signature is present, go ahead and gather information for the paths
|
|
|
|
// [carry on]
|
|
// Get info from the registry, and create the container
|
|
|
|
|
|
// -- DiscoverAnyIE5Settings
|
|
// We're going to call this function if we haven't any IE4 settings to upgrade,
|
|
// but _before_ we check for IE3,
|
|
|
|
DWORD GetIEVersion();
|
|
|
|
BOOL CConMgr::DiscoverAnyIE5Settings(IE5_REGISTRYSET* pie5rs)
|
|
{
|
|
// Let's consider the following scenario:
|
|
// User A logs on to the machine with IE4 installed; installs IE5, and then shuts down
|
|
// the machine. User B comes along, but IE5 hasn't been installed yet. If User B has
|
|
// admin privileges, install will continue, BUT still not have any IE4/5 settings.
|
|
// Which resulted in skipping DiscoverIE4Settings. However, we don't want to look
|
|
// at IE3's settings.
|
|
|
|
// If we're installing over IE4/2/5, but we don't have any settings for this user,
|
|
// we must avoid an IE3 upgrade. Instead, short circuit to use last-minute info-gathering
|
|
// For IE3, use a shared cache
|
|
DWORD dwVer = GetIEVersion();
|
|
|
|
// We're going to use a shared cache for IE3 and Win9x users.
|
|
// Upgrading over IE4 and 5 -- for users who have logged in before,
|
|
// their signatures shoudl be in place already. In those cases, we shouldn't
|
|
// be in this function anyway. For other users, we'll use the shared cache.
|
|
// This is the first time for the machine.
|
|
if ((dwVer==3) && pie5rs->IsFirstTimeForMachine())
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pie5rs->AttemptToUseSharedCache(NULL, 0);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID CConMgr::DiscoverRegistrySettings(IE5_REGISTRYSET* pie5rs)
|
|
{
|
|
LOG_UPGRADE_DATA("Attempting to discover IE4 settings...\n");
|
|
|
|
if (DiscoverIE4Settings(pie5rs))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
|
|
#ifndef UNIX
|
|
if (GlobalPlatformType == PLATFORM_TYPE_WINNT)
|
|
#else
|
|
if (GlobalPlatformType == PLATFORM_TYPE_UNIX)
|
|
#endif /* UNIX */
|
|
{
|
|
LOG_UPGRADE_DATA("This is NT. Fuhgedabout IE3 et al settings...\n");
|
|
|
|
// This will override NT's default behaviour to use per-user containers.
|
|
pie5rs->SetWorkingContainer(CONTENT);
|
|
if (!pie5rs->GetPerUserStatus())
|
|
{
|
|
pie5rs->AttemptToUseSharedCache(NULL, 0);
|
|
}
|
|
|
|
// Suppose this is an install over NT. Each user should get a per-user, non-roaming
|
|
// path by default. The values we'd pick up from SHFolderGetPath will be okay; but, we need to make
|
|
// sure that we treat this as a per-user container.
|
|
|
|
// Suppose we upgraded from some previous version of Win9x to NT5. There are eight scenarios:
|
|
// nothing : in which case, we do as above
|
|
// IE3 : same; need to delete old cache
|
|
// IE4 -- single-user machine:same as fresh install; need to delete old cache.
|
|
// -- shared cache : same as fresh install
|
|
// -- per user cache : preserve path
|
|
// -- moved cache : preserve path
|
|
// IE5 -- single-user machine:same as fresh install; need to delete old cache.
|
|
// -- shared cache : preserve shared path
|
|
// -- per user cache : preserve path
|
|
// -- moved cache : preserve path
|
|
|
|
// If an admin wants to use a shared cache under NT5, s/he will have to set
|
|
// HKCU/Shell Folders and User Shell Folders to point to the common path
|
|
// AND {HKCU|HKLM}/blah/PerUserItem to 0 (or delete the HKCU value).
|
|
if ((GetIEVersion()==3) && pie5rs->IsFirstTimeForMachine())
|
|
{
|
|
IE3_REGISTRYSET ie3rs;
|
|
TCHAR szTemp[MAX_PATH];
|
|
DWORD cbLimit;
|
|
if ((ie3rs.InitialiseKeys()==ERROR_SUCCESS)
|
|
&&
|
|
(ie3rs.GetContentDetails(szTemp, cbLimit)))
|
|
{
|
|
DeleteCachedFilesInDir(szTemp);
|
|
}
|
|
}
|
|
goto exit;
|
|
}
|
|
|
|
LOG_UPGRADE_DATA("Attempting to discover any IE5 settings...\n");
|
|
if (DiscoverAnyIE5Settings(pie5rs))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
LOG_UPGRADE_DATA("Attempting to discover any IE3 settings...\n");
|
|
DiscoverIE3Settings(pie5rs);
|
|
|
|
exit:
|
|
LOG_UPGRADE_DATA("Flushing shell folders cache...\n");
|
|
pie5rs->SetIfFirstTime();
|
|
FlushShellFolderCache();
|
|
}
|
|
|
|
// -- AttemptToUseSharedCache
|
|
// Given a path (and limit) attempt to use the path for a shared location.
|
|
// If the path is null, then try to use any value if present, else invent one.
|
|
|
|
VOID IE5_REGISTRYSET::AttemptToUseSharedCache(PTSTR pszPath, DWORD ckbLimit)
|
|
{
|
|
TCHAR szSharedPath[MAX_PATH];
|
|
DWORD cc = ARRAY_ELEMENTS(szSharedPath);
|
|
|
|
REGISTRY_OBJ roContent(&m_roHKLMCache, g_szSubKey[CONTENT], CREATE_KEY_IF_NOT_EXISTS);
|
|
if ((roContent.GetStatus()==ERROR_SUCCESS)
|
|
&&
|
|
(roContent.GetValue(CACHE_PATH_VALUE, (LPBYTE)szSharedPath, &cc)==ERROR_SUCCESS))
|
|
{
|
|
LOG_UPGRADE_DATA("Found a shared cache location...\n");
|
|
goto write_value;
|
|
}
|
|
|
|
if (pszPath!=NULL)
|
|
{
|
|
LOG_UPGRADE_DATA(pszPath);
|
|
LOG_UPGRADE_DATA("\n is ");
|
|
GetUserName(szSharedPath, &cc);
|
|
|
|
// We're going to ignore just the user name, during this comparison. And
|
|
// if it's in the profiles directory, fuhgedaboutit.
|
|
if (m_fProfiles && !StrCmpNI(m_szProfilePath, pszPath, cbP-cc))
|
|
{
|
|
pszPath = NULL;
|
|
LOG_UPGRADE_DATA("not okay \n");
|
|
goto carryon;
|
|
}
|
|
LOG_UPGRADE_DATA("okay \n");
|
|
strcpy(szSharedPath, pszPath);
|
|
}
|
|
|
|
carryon:
|
|
if (pszPath==NULL)
|
|
{
|
|
memcpy(szSharedPath, m_szSharedPath, (cbS+1)*sizeof(TCHAR));
|
|
CleanPath(szSharedPath);
|
|
LOG_UPGRADE_DATA("Using a constructed shared path\n");
|
|
}
|
|
|
|
// We've finally decided on the path. Now let's write the value into the registry.
|
|
roContent.SetValue(CACHE_PATH_VALUE, szSharedPath, REG_SZ);
|
|
SetWorkingContainer(CONTENT);
|
|
SetPerUserStatus(FALSE);
|
|
SetLimit(szSharedPath, ckbLimit);
|
|
|
|
write_value:
|
|
LOG_UPGRADE_DATA("The shared cache will be located at ");
|
|
LOG_UPGRADE_DATA(szSharedPath);
|
|
LOG_UPGRADE_DATA("\n");
|
|
|
|
// This will take care of HKCU
|
|
CHAR szScratch[MAX_PATH];
|
|
#ifndef UNIX
|
|
if (!NormalisePath(szSharedPath, TEXT("%SystemRoot%"), szScratch, sizeof(szScratch)))
|
|
#else
|
|
if (!NormalisePath(szSharedPath, TEXT("%USERPROFILE%"), szScratch, sizeof(szScratch)))
|
|
#endif /* UNIX */
|
|
{
|
|
strncpy(szScratch, szSharedPath, MAX_PATH);
|
|
}
|
|
if (m_roUserShellFolder.SetValue(g_szOldSubKey[CONTENT], szScratch, REG_EXPAND_SZ)==ERROR_SUCCESS)
|
|
{
|
|
#ifndef UNIX
|
|
DWORD dwType = REG_SZ;
|
|
m_roShellFolder.SetValue(g_szOldSubKey[CONTENT], szSharedPath, dwType);
|
|
#else
|
|
m_roShellFolder.SetValue(g_szOldSubKey[CONTENT], szScratch, REG_EXPAND_SZ);
|
|
#endif /* UNIX */
|
|
}
|
|
}
|
|
|
|
|
|
// -- CleanPath
|
|
// Given a path, strip away any trailing content.ie5's, and if necessary, add a trailing brand mark,
|
|
// i.e. "Temporary Internet Files" or localised version.
|
|
|
|
VOID CleanPath(PTSTR pszPath)
|
|
{
|
|
DWORD ccPath = strlen(pszPath);
|
|
PTSTR pszLastSep = pszPath + ccPath;
|
|
|
|
// Now we're at the null terminator, but if the last character is also a separator, we want
|
|
// to skip that too.
|
|
if (*(pszLastSep-1)==DIR_SEPARATOR_CHAR)
|
|
{
|
|
pszLastSep--;
|
|
}
|
|
BOOL fSlash;
|
|
// Strip away any "content.ie5"'s from the path
|
|
for (;(fSlash = ScanToLastSeparator(pszPath, &pszLastSep));)
|
|
{
|
|
if (StrCmpNI((pszLastSep+1), TEXT("content.ie"), ARRAY_ELEMENTS(TEXT("content.ie"))-1))
|
|
{
|
|
break;
|
|
}
|
|
*pszLastSep = '\0';
|
|
}
|
|
|
|
// Load temp int files
|
|
TCHAR szBrand[MAX_PATH];
|
|
DWORD ccBrand = 0;
|
|
|
|
ccBrand = LoadString(GlobalDllHandle, g_dwCachePathResourceID[CONTENT], szBrand, ARRAY_ELEMENTS(szBrand));
|
|
|
|
// The following fragment should never happen, but just in case...
|
|
if (!ccBrand)
|
|
{
|
|
ccBrand = sizeof(TEXT("Temporary Internet Files"));
|
|
memcpy(szBrand, TEXT("Temporary Internet Files"), ccBrand);
|
|
ccBrand /= sizeof(TCHAR);
|
|
ccBrand--;
|
|
}
|
|
|
|
// If "Temporary Internet Files" doesn't trail the path, add it.
|
|
if (!fSlash)
|
|
{
|
|
*pszLastSep++ = DIR_SEPARATOR_CHAR;
|
|
*pszLastSep = '\0';
|
|
}
|
|
else
|
|
{
|
|
pszLastSep++;
|
|
}
|
|
if (StrCmpNI((pszLastSep), szBrand, ccBrand))
|
|
{
|
|
while (*pszLastSep && *pszLastSep!=DIR_SEPARATOR_CHAR)
|
|
{
|
|
pszLastSep++;
|
|
}
|
|
if (!*pszLastSep && (*(pszLastSep-1)!=DIR_SEPARATOR_CHAR))
|
|
{
|
|
*pszLastSep = DIR_SEPARATOR_CHAR;
|
|
pszLastSep++;
|
|
}
|
|
else if (*pszLastSep)
|
|
{
|
|
pszLastSep++;
|
|
}
|
|
memcpy(pszLastSep, szBrand, ccBrand*sizeof(TCHAR));
|
|
}
|
|
*(pszLastSep+ccBrand)='\0';
|
|
}
|
|
|
|
DWORD GetIEVersion()
|
|
{
|
|
DWORD dwVer = 0;
|
|
|
|
REGISTRY_OBJ roVersion(HKEY_LOCAL_MACHINE, OLD_VERSION_KEY);
|
|
TCHAR szKey[MAX_PATH];
|
|
DWORD cb = ARRAY_ELEMENTS(szKey);
|
|
|
|
if ((roVersion.GetStatus()!=ERROR_SUCCESS)
|
|
||
|
|
(roVersion.GetValue(OLD_VERSION_VALUE, (LPBYTE)szKey, &cb)!=ERROR_SUCCESS))
|
|
{
|
|
// This should never happen during a proper setup.
|
|
// In case it does, however, we'll just use construct IE5's default settings.
|
|
return 0;
|
|
}
|
|
|
|
PTSTR psz = szKey;
|
|
PTSTR pszFirst = szKey;
|
|
// Get the major version number
|
|
while (*psz!='.')
|
|
{
|
|
psz++;
|
|
}
|
|
*psz = '\0';
|
|
dwVer = (DWORD)StrToInt(pszFirst);
|
|
|
|
if (dwVer==4)
|
|
{
|
|
psz++;
|
|
// Skip the second number
|
|
while (*psz!='.')
|
|
{
|
|
psz++;
|
|
}
|
|
pszFirst = psz;
|
|
psz++;
|
|
while (*psz!='.')
|
|
{
|
|
psz++;
|
|
}
|
|
*psz = '\0';
|
|
dwVer = ((DWORD)StrToInt(pszFirst))==0 ? 3 : 4;
|
|
}
|
|
|
|
return dwVer;
|
|
}
|
|
|