Windows2003-3790/inetcore/wininet/urlcache/401imprt.cxx
2020-09-30 16:53:55 +02:00

1275 lines
40 KiB
C++

#include <cache.hxx>
#include "401imprt.hxx"
#include "401inc.hxx"
#ifdef UNICODE
#error "401imprt.cxx doesn't support UNICODE compilation."
#endif
#define PRE5_CACHE_KEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache"
#define IE401_HIST_ROOT "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Extensible Cache"
//IE401_PER_USER_CACHE_LOCATION is in HKCU
#define IE401_PER_USER_CACHE_LOCATION \
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"
#define IE401_PER_USER_CACHE_KEY "Cache"
//IE401_ONE_USER_CACHE_LOCATION is in HKLM
#define IE401_ONE_USER_CACHE_LOCATION \
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Content"
#define IE401_ONE_USER_CACHE_KEY "CachePath"
#define MSHIST_DIR_SZ "MSHIST011998020119980225"##FILENAME_SEPARATOR_STR
#define MSHIST_KEY_SZ "MSHIST011998020119980225"
#define MSHIST_SZ "MSHIST"
#define MSHIST_PREFIX_SZ ":1998010119980101:"
#define VISITED_PREFIX_SZ "Visited:"
#define INDEX_DAT_SZ "index.dat"
#define CACHE_LIMIT_SZ "CacheLimit"
#define CACHE_OPTIONS_SZ "CacheOptions"
#define CACHE_PATH_SZ "CachePath"
#define CACHE_PREFIX_SZ "CachePrefix"
//----------------------------------------
//The following tructures and macro, _HISTDATA_V001 and SET_HISTORY_FLAG()
//allow us to notify members of the Visited: cache that they are to be
//listed in the History view. The structure was cut'n'pasted from
//shdocvw\urlhist.cpp and any changes made to the original need
//to be reflected here as well.
#define PIDISF_HISTORY 0x10000000
#define PID_INTSITE_TITLE 16
//** BUGBUG
struct _HISTDATA_V001
{
UINT cbSize : 16; // size of this header
UINT cbVer : 16; // version
DWORD dwFlags; // PID_INTSITE_FLAGS (PIDISF_ flags)
DWORD dwWatch; // PID_INTSITE_WATCH (PIDISM_ flags)
DWORD dwVisits; // PID_INTSITE_VISITCOUNT
};
#define SET_HISTORY_FLAG(lpHeaderInfo) \
(((_HISTDATA_V001*)lpHeaderInfo)->dwFlags |= PIDISF_HISTORY)
//
// Right after HISTDATA (always at cbSize), we have optional (typically
// variable length) data which has following data structure. It may have
// more than one but always has a null-terimiator (cbExtra == 0).
//
//HISTEXTRA is also cut'n'pasted from shdocvw.
struct HISTEXTRA
{
UINT cbExtra : 16;
UINT idExtra : 8; // PID_INTSITE_*
UINT vtExtra : 8; // VT_*
BYTE abExtra[1]; // abExtra[cbExtra-4];
};
// HISTEXTRA without the abExtra ==> (sizeof(HISTEXTRA) - sizeof(BYTE))
#define HISTEXTRA_HEAD_SIZE 4
//-----------------------------------------
BOOL IsPerUserCache();
namespace ie401
{
//--------------------------------------------------------
// The code that enumerates through a IE401 index.dat file is provided
//by IE401IndexFile. Classes derived from IE401IndexFile override HandleHashElement
//to handle each HASH_ELEMENT as the index file is enumerated.
// IE401IndexFile::Import401Url is provided to import URLs without overwriting
//already existing entries.
class IE401IndexFile
{
public:
// EnumHashValues enumerates hash tables, calling HandleHashElement for each.
virtual BOOL EnumHashValues();
protected:
IE401IndexFile( LPCSTR szFilename);
IE401IndexFile();
virtual ~IE401IndexFile();
// given by derived class
virtual BOOL HandleHashElement( ie401::HASH_ITEM* pEntry) = 0;
// probably useful to many, default URL import. Not for REDIRs.
virtual BOOL Import401Url( ie401::URL_FILEMAP_ENTRY* pEntry);
BYTE* m_pBuf;
};
//--------------------------------------------------------
// IE401Visited overrides HandleHashElement to import all URLs,
//translating CEI to its current format.
// All the dependencies on the change in CEI format are
//contained in UpgradeHeaderData.
class IE401Visited : public IE401IndexFile
{
public:
IE401Visited( LPCSTR szFilename);
protected:
IE401Visited() {}
virtual BOOL HandleHashElement( ie401::HASH_ITEM* pEntry);
virtual BOOL Import401UrlTranslatingCEI( ie401::URL_FILEMAP_ENTRY* pEntry);
virtual BOOL UpgradeHeaderData(
IN const CHAR* pIn,
OUT CHAR* pOut,
IN OUT DWORD* pcbOutSize);
};
//--------------------------------------------------------
// IE401History overrides HandleHashElement to import all URLs
//and mark them in the Visited: container.
// All the dependencies on the format for the Visited mark
//are contained in MarkUrlAsVisited.
//(colliding items are not imported and associated data
//files are not copied.)
class IE401History : public IE401IndexFile
{
public:
IE401History( LPCSTR szFilename);
protected:
IE401History() {}
virtual BOOL HandleHashElement( ie401::HASH_ITEM* pEntry);
static BOOL MarkUrlAsVisited( LPSTR szUrlName);
};
//--------------------------------------------------------
// pre-declaration included so IE401Redirects can be declared as a friend
class IE401Redirects;
// IE401Content overrides HandleHashElement to import all URLs
//and also copy associated data files.
//(colliding items are not imported)
class IE401Content : public IE401IndexFile
{
public:
IE401Content( LPCSTR szFilename);
friend IE401Redirects;
protected:
IE401Content() {}
virtual BOOL HandleHashElement( ie401::HASH_ITEM* pEntry);
// Extends the default to import files
BOOL Import401UrlWithFile( ie401::URL_FILEMAP_ENTRY* pEntry);
CHAR m_szRootPath[MAX_PATH];
DWORD m_cbRootPathLength;
DWORD m_nDirs;
CHAR m_szDir[DEFAULT_MAX_DIRS][DIR_NAME_SIZE + 1];
};
//--------------------------------------------------------
// IE401Redirects override HandleHashElement to import redirects.
// This should be done to an index file after IE401Content has
//enumerated over it, so the constructor takes a IE401Content object
//rather than a filename. This IE401Content represents a process
//that is finished, so its functionality is taken away.
// Importing redirects is done with a separate enumerator than
//IE401Content since its less work then retooling IE401IndexFile
//to enumerate an arbitrary number of times.
class IE401Redirects : public IE401IndexFile
{
public:
IE401Redirects( IE401Content* pContent);
protected:
IE401Redirects() {}
virtual BOOL HandleHashElement( ie401::HASH_ITEM* pEntry);
BOOL Import401Redirect( ie401::REDIR_FILEMAP_ENTRY* pEntry);
};
//******************************************************
//
// class OutputStream - utility
//
// outputs data to a buffer, tracking buffer used
//and checking for overflow.
class OutputStream
{
public:
OutputStream( VOID* pBuffer, DWORD cbBufferSize)
: m_pBuffer( (BYTE*)pBuffer), m_cbBufferSize( cbBufferSize), m_cbPosition(0)
{
}
BOOL Memcpy( const VOID* pSource, DWORD cbSize)
{
if( cbSize + m_cbPosition <= m_cbBufferSize)
{
memcpy(&m_pBuffer[m_cbPosition], (BYTE*)pSource, cbSize);
m_cbPosition += cbSize;
return TRUE;
}
else
return FALSE;
}
BOOL CopyAnsiToUnicode( const CHAR* pSource, DWORD cSize)
{
if( m_cbPosition + cSize * sizeof(WCHAR) / sizeof(CHAR)
<= m_cbBufferSize)
{
DWORD dwSizeCopied;
// the semantics of MultiByteToWideChar is different
//if you give it a zero-length buffer.
INET_ASSERT( m_cbBufferSize - m_cbPosition != 0);
dwSizeCopied =
MultiByteToWideChar( CP_ACP, 0, pSource, cSize,
(WCHAR*)&m_pBuffer[m_cbPosition],
(m_cbBufferSize - m_cbPosition) / sizeof(WCHAR));
if( dwSizeCopied != 0)
{
m_cbPosition += dwSizeCopied * sizeof(WCHAR);
return TRUE;
}
else
return FALSE;
}
else
return FALSE;
}
DWORD GetFinalLength()
{
return m_cbPosition;
}
private:
BYTE* m_pBuffer;
DWORD m_cbBufferSize, m_cbPosition;
};
//*************************************************************************
//
// IE401IndexFile
//
// On creation, load the contents of the given file into memory.
IE401IndexFile::IE401IndexFile( LPCSTR szFilename)
{
m_pBuf = NULL;
// load the file into the buffer
DWORD cbBufSize;
if( ReadFileToBuffer( szFilename, &m_pBuf, &cbBufSize) == FALSE)
{
if( m_pBuf != NULL)
{
delete [] m_pBuf;
m_pBuf = NULL;
}
}
else if( cbBufSize < sizeof(_MEMMAP_HEADER_SMALL)
|| strcmp((LPSTR) m_pBuf, "Client UrlCache MMF Ver 4.7"))
{
// If this file doesn't even have a memmap header, forget it.
// Now all derived classes can assume they have at least a memmap header
//if m_pBuf != NULL
delete [] m_pBuf;
m_pBuf = NULL;
}
}
// Default constructor made protected to prevent direct creation
IE401IndexFile::IE401IndexFile()
: m_pBuf(NULL)
{
}
IE401IndexFile::~IE401IndexFile()
{
if( m_pBuf != NULL)
delete [] m_pBuf;
}
//---------------------------------------------------
//
// Enumerate through the entries in an ie401 index
//file, calling HandleHashElement on each entry.
BOOL IE401IndexFile::EnumHashValues()
{
BOOL retVal = FALSE;
if( m_pBuf == NULL)
goto doneEnumHashValues;
HASH_FILEMAP_ENTRY* pTable;
HASH_ITEM* pItem;
// pTable is located by an offset which is located at dwHashTableOffset
pTable = (HASH_FILEMAP_ENTRY*)(m_pBuf + (((_MEMMAP_HEADER_SMALL*)m_pBuf)->dwHashTableOffset));
// The first location in the table follows immediately after the HASH_FILEMAP_ENTRY pTable
pItem = (HASH_ITEM*)(pTable + 1);
if (pTable->dwSig != SIG_HASH)
goto doneEnumHashValues;
do // Scan the list of tables.
{
// Scan the current table.
for (; (LPBYTE)pItem < (LPBYTE)pTable + BYTES_PER_TABLE; pItem++)
{
// call virtual entry handler
if( HandleHashElement( pItem) == FALSE)
goto doneEnumHashValues;
}
// Follow the link to the next table.
if (!pTable->dwNext)
{
pTable = NULL;
}
else
{
// Validate the table signature and sequence number.
DWORD nBlock;
nBlock = pTable->nBlock;
pTable = (HASH_FILEMAP_ENTRY*) (m_pBuf + pTable->dwNext);
if (pTable->dwSig != SIG_HASH || pTable->nBlock != nBlock + 1)
goto doneEnumHashValues;
// Set pointer to first location in table.
pItem = (HASH_ITEM*) (pTable + 1);
}
}
while (pTable);
retVal = TRUE;
doneEnumHashValues:
return retVal;
}
//---------------------------------------------------
//
// Imports an URL entry without overwriting existing
//cache entries or copying any associated data files.
BOOL IE401IndexFile::Import401Url( ie401::URL_FILEMAP_ENTRY* pEntry)
{
BOOL retVal = FALSE;
// don't import Url if it is already in the buffer
if( GetUrlCacheEntryInfo( (LPSTR)((BYTE*)pEntry + pEntry->UrlNameOffset), NULL, 0) == TRUE
|| GetLastError() != ERROR_FILE_NOT_FOUND)
{
goto doneImport401Url;
}
if( pEntry->FileSize != 0)
{
INET_ASSERT(0); // Are you importing URL cache entries with external data?
goto doneImport401Url;
}
if( !CommitUrlCacheEntry(
(LPCSTR)((BYTE*)pEntry + pEntry->UrlNameOffset),
NULL,
*LONGLONG_TO_FILETIME(&pEntry->ExpireTime),
*LONGLONG_TO_FILETIME(&pEntry->LastModifiedTime),
pEntry->CacheEntryType,
pEntry->HeaderInfoOffset != NULL ?
(BYTE*)((BYTE*)pEntry + pEntry->HeaderInfoOffset) : NULL,
pEntry->HeaderInfoSize,
pEntry->FileExtensionOffset != 0 ?
(LPCSTR)((BYTE*)pEntry + pEntry->FileExtensionOffset) : NULL,
NULL))
goto doneImport401Url;
CACHE_ENTRY_INFO cei;
cei.dwStructSize = sizeof(cei);
cei.LastAccessTime = *LONGLONG_TO_FILETIME(&pEntry->LastAccessedTime);
cei.dwHitRate = pEntry->NumAccessed;
cei.ExpireTime = *LONGLONG_TO_FILETIME(&pEntry->ExpireTime);
cei.LastModifiedTime = *LONGLONG_TO_FILETIME(&pEntry->LastModifiedTime);
if( !SetUrlCacheEntryInfo(
(LPCSTR)((BYTE*)pEntry + pEntry->UrlNameOffset),
&cei,
CACHE_ENTRY_ACCTIME_FC | CACHE_ENTRY_HITRATE_FC
| CACHE_ENTRY_EXPTIME_FC | CACHE_ENTRY_MODTIME_FC))
goto doneImport401Url;
retVal = TRUE;
doneImport401Url:
return retVal;
}
//************************************************************************8
//
// IE401Visited : public IE401IndexFile
//
IE401Visited::IE401Visited( LPCSTR szFilename) : IE401IndexFile( szFilename)
{
}
// imports only URLs using Import401Url- nothing special
BOOL IE401Visited::HandleHashElement( ie401::HASH_ITEM* pEntry)
{
// No reserved bits should be set.
INET_ASSERT (!(pEntry->dwHash & HASH_BIT_RESERVED));
if( !(pEntry->dwHash & HASH_BIT_NOTURL)
&& ((ie401::FILEMAP_ENTRY*)(m_pBuf + pEntry->dwOffset))->dwSig == SIG_URL)
{
Import401UrlTranslatingCEI( (ie401::URL_FILEMAP_ENTRY*)(m_pBuf + pEntry->dwOffset));
}
// after wrapping above in try-catch block, return FALSE on unhandled exception.
return TRUE;
}
//----------------------------------------
//
// IE401Visited::Import401UrlTranslatingCEI
//
// Very much like Import401Url except it makes
//a call to UpgradeHeaderData before calling CommitCacheEntry.
BOOL IE401Visited::Import401UrlTranslatingCEI( ie401::URL_FILEMAP_ENTRY* pEntry)
{
BOOL retVal = FALSE;
// don't import Url if it is already in the buffer
if( GetUrlCacheEntryInfo( (LPSTR)((BYTE*)pEntry + pEntry->UrlNameOffset), NULL, 0) == TRUE
|| GetLastError() != ERROR_FILE_NOT_FOUND)
{
goto doneImport401UrlTranslatingCEI;
}
if( pEntry->FileSize != 0)
{
INET_ASSERT(0); // Are you importing URL cache entries with external data?
goto doneImport401UrlTranslatingCEI;
}
DWORD cbHeaderBufSize;
//BUGBUG: Does shdocvw still obey MAX_CACHE_ENTRY_INFO_SIZE
//in the version being imported?
CHAR szHeaderBuf[ MAX_CACHE_ENTRY_INFO_SIZE];
cbHeaderBufSize = MAX_CACHE_ENTRY_INFO_SIZE;
if( pEntry->HeaderInfoOffset != 0)
{
if( UpgradeHeaderData( (CHAR*)((BYTE*)pEntry + pEntry->HeaderInfoOffset),
szHeaderBuf, &cbHeaderBufSize) != TRUE)
{
goto doneImport401UrlTranslatingCEI;
}
}
else
cbHeaderBufSize = 0;
if( !CommitUrlCacheEntry(
(LPCSTR)((BYTE*)pEntry + pEntry->UrlNameOffset),
NULL,
*LONGLONG_TO_FILETIME(&pEntry->ExpireTime),
*LONGLONG_TO_FILETIME(&pEntry->LastModifiedTime),
pEntry->CacheEntryType,
cbHeaderBufSize != 0 ?
(BYTE*)szHeaderBuf : NULL,
cbHeaderBufSize,
pEntry->FileExtensionOffset != 0 ?
((CHAR*)pEntry + pEntry->FileExtensionOffset) : NULL,
NULL))
goto doneImport401UrlTranslatingCEI;
CACHE_ENTRY_INFO cei;
cei.dwStructSize = sizeof(cei);
cei.LastAccessTime = *LONGLONG_TO_FILETIME(&pEntry->LastAccessedTime);
cei.dwHitRate = pEntry->NumAccessed;
cei.ExpireTime = *LONGLONG_TO_FILETIME(&pEntry->ExpireTime);
cei.LastModifiedTime = *LONGLONG_TO_FILETIME(&pEntry->LastModifiedTime);
if( !SetUrlCacheEntryInfo(
(LPCSTR)((BYTE*)pEntry + pEntry->UrlNameOffset),
&cei,
CACHE_ENTRY_ACCTIME_FC | CACHE_ENTRY_HITRATE_FC
| CACHE_ENTRY_EXPTIME_FC | CACHE_ENTRY_MODTIME_FC))
goto doneImport401UrlTranslatingCEI;
retVal = TRUE;
doneImport401UrlTranslatingCEI:
return retVal;
}
BOOL IE401Visited::UpgradeHeaderData(
IN const CHAR* pIn,
OUT CHAR* pOut,
IN OUT DWORD* pcbOutSize)
{
BOOL retVal = FALSE;
OutputStream op( pOut, *pcbOutSize);
// The header info struct contains a HISTDATA followed by
//a list of HISTEXTRAs.. Their sizes can vary but they should
//be adjacent. The last HISTEXTRA has a cbExtra of 0 and a sizeof(UINT).
// When we import a HISTEXTRA (idExtra = PID_INTSITE_TITLE) then
//we must convert the attached string from ANSI to Unicode
HISTEXTRA* pExtra = NULL;
//first copy the HISTDATA
if( op.Memcpy( pIn, ((_HISTDATA_V001*)pIn)->cbSize) == FALSE)
goto doneUpgradeCEIData;
for(pExtra = (HISTEXTRA*) (pIn + ((_HISTDATA_V001*)pIn)->cbSize);
pExtra->cbExtra != 0;
pExtra = (HISTEXTRA*)((BYTE*)pExtra + pExtra->cbExtra))
{
if( pExtra->idExtra != PID_INTSITE_TITLE)
{
if( op.Memcpy( pExtra, pExtra->cbExtra) == FALSE)
goto doneUpgradeCEIData;
}
else
{
HISTEXTRA* pNew = (HISTEXTRA*)((BYTE*)pOut + op.GetFinalLength());
// copy the HISTEXTRA head
INET_ASSERT( pExtra->cbExtra >= HISTEXTRA_HEAD_SIZE);
if( op.Memcpy( pExtra, HISTEXTRA_HEAD_SIZE) == FALSE)
goto doneUpgradeCEIData;
if( op.CopyAnsiToUnicode( (CHAR*)&(pExtra->abExtra),
pExtra->cbExtra - HISTEXTRA_HEAD_SIZE)
== FALSE)
goto doneUpgradeCEIData;
pNew->vtExtra = VT_LPWSTR;
// cbExtra(size) is the change in position of the output stream.
pNew->cbExtra = ((BYTE*)pOut + op.GetFinalLength()) - (BYTE*)pNew;
}
}
// the final member in the list is just a DWORD, value == 0.
// determined from assertions in Urlhist.cpp:
//ASSERT( phext->cbExtra == 0); // terminator
//ASSERT( (LPBYTE)phdNew+cbHeader == (LPBYTE)phext+SIZEOF(DWORD) );
if( op.Memcpy( pExtra, sizeof(DWORD)) == FALSE)
goto doneUpgradeCEIData;
retVal = TRUE;
doneUpgradeCEIData:
if( retVal == TRUE)
*pcbOutSize = op.GetFinalLength();
return retVal;
}
//************************************************************************8
//
// IE401History : public IE401IndexFile
//
IE401History::IE401History( LPCSTR szFilename) : IE401IndexFile( szFilename)
{
}
// imports only URLs using Import401Url then marks them
//as Visited
BOOL IE401History::HandleHashElement( ie401::HASH_ITEM* pEntry)
{
// No reserved bits should be set.
INET_ASSERT (!(pEntry->dwHash & HASH_BIT_RESERVED));
if( !(pEntry->dwHash & HASH_BIT_NOTURL)
&& ((ie401::FILEMAP_ENTRY*)(m_pBuf + pEntry->dwOffset))->dwSig == SIG_URL)
{
ie401::URL_FILEMAP_ENTRY* pUrlToImport = (ie401::URL_FILEMAP_ENTRY*)(m_pBuf + pEntry->dwOffset);
if( Import401Url( pUrlToImport) == TRUE)
MarkUrlAsVisited( (CHAR*)pUrlToImport + pUrlToImport->UrlNameOffset);
}
// after wrapping above in try-catch block, return FALSE on unhandled exception.
return TRUE;
}
// Marks an Url given with a history prefix in the Visited container
BOOL IE401History::MarkUrlAsVisited( LPSTR szUrlName)
{
BOOL retVal = FALSE;
LPCACHE_ENTRY_INFO pCei = NULL;
DWORD cbCei = 0;
//I'm changing the string from "MSHIST_PREFIX_SZhttp:\\www.urlname"
//to "VISITED_PREFIX_SZhttp:\\www.urlname" in order to locate/change
//the cache entry.
//This requires backing up the old prefix, and setting a new pointer
//to the correct location to place the new prefix. Once the modified
//szUrlName is used the old prefix is always restored.
// backup the old prefix
CHAR szBackup[sizeof(MSHIST_PREFIX_SZ)];
memcpy( szBackup, szUrlName, sizeof(MSHIST_PREFIX_SZ));
// Move the pointer to later in the string so that the new, smaller
//prefix fits, and put the new prefix there.
LPSTR szModifiedUrl = szUrlName + sizeof(MSHIST_PREFIX_SZ) - sizeof(VISITED_PREFIX_SZ);
memcpy( szModifiedUrl, VISITED_PREFIX_SZ, sizeof(VISITED_PREFIX_SZ) - 1);
// Get the cei
if( GetUrlCacheEntryInfo( szModifiedUrl, NULL, &cbCei) == TRUE)
goto doneMarkUrlAsVisited;
pCei = (CACHE_ENTRY_INFO*)(new BYTE[cbCei]);
if( pCei == NULL)
goto doneMarkUrlAsVisited;
if( GetUrlCacheEntryInfo( szModifiedUrl, pCei, &cbCei) != TRUE)
goto doneMarkUrlAsVisited;
if( pCei->dwHeaderInfoSize < sizeof(_HISTDATA_V001))
goto doneMarkUrlAsVisited;
// set the Visited flag
SET_HISTORY_FLAG(pCei->lpHeaderInfo);
CHAR* pStrStr;
if( pCei->lpHeaderInfo != NULL
&& (pStrStr = StrStr( pCei->lpHeaderInfo, CACHE_CONTROL_SZ)) != NULL
&& (pStrStr = StrStr( pStrStr, MUST_REVALIDATE_SZ)) != NULL)
{
pCei->CacheEntryType |= MUST_REVALIDATE_CACHE_ENTRY;
}
if( CommitUrlCacheEntry( szModifiedUrl, NULL, pCei->ExpireTime,
pCei->LastModifiedTime, pCei->CacheEntryType, (BYTE*)pCei->lpHeaderInfo,
pCei->dwHeaderInfoSize, pCei->lpszFileExtension, NULL) != TRUE)
goto doneMarkUrlAsVisited;
if( SetUrlCacheEntryInfo(
szModifiedUrl,
pCei,
CACHE_ENTRY_ACCTIME_FC | CACHE_ENTRY_HITRATE_FC | CACHE_ENTRY_EXPTIME_FC ) != TRUE)
goto doneMarkUrlAsVisited;
retVal = TRUE;
doneMarkUrlAsVisited:
memcpy( szUrlName, szBackup, sizeof(MSHIST_PREFIX_SZ));
if( pCei != NULL)
delete [] pCei;
return retVal;
}
//************************************************************************8
//
// IE401Content : public IE401IndexFile
//
// on the creation of a IE401Content object, we
//prepare for the enumeration of its entries by:
// - identifying the subdirectories of the old cache
// - register each subdirectory in the new cache
// - move each subdirectory into the new cache's location
IE401Content::IE401Content( LPCSTR szFilename)
: IE401IndexFile( szFilename)
{
BOOL fConstructionSuccessful = FALSE;
// make sure the index file loaded alright.
if( m_pBuf == NULL)
goto exitIE401Construct;
// ConfigInfo is retrieved since it contains the path of the new cachefile.
CACHE_CONFIG_INFO sConfigInfo;
DWORD dwTemp;
if( GetUrlCacheConfigInfo( &sConfigInfo,
&(dwTemp = sizeof(sConfigInfo)),
CACHE_CONFIG_CONTENT_PATHS_FC)
== FALSE)
{
goto exitIE401Construct;
}
// get the target path for subcontainer move
m_cbRootPathLength = lstrlen( sConfigInfo.CachePath);
memcpy( m_szRootPath, sConfigInfo.CachePath, m_cbRootPathLength + 1);
//target path example: m_szRootPath = "c:\winnt\content.ie5"
// get the source path for the subcontainers from the given filename
DWORD cbSourcePathLength;
CHAR szSourcePath[MAX_PATH];
cbSourcePathLength = lstrlen( szFilename);
memcpy( szSourcePath, szFilename, cbSourcePathLength + 1);
// clip off the filename so that we have just the path.
while( cbSourcePathLength > 0 && szSourcePath[cbSourcePathLength] != FILENAME_SEPARATOR)
{
cbSourcePathLength--;
}
szSourcePath[ ++cbSourcePathLength] = '\0';
//source path example: szSourcePath = "c:\winnt\content\"
// enumerate through the subdirectories,
// attempt to register that directory in the new cache
// then move the old directory into the new cache.
// If the directory cannot be registered or moved, then
//m_szDir contains "" for that directory index.
m_nDirs = ((_MEMMAP_HEADER_SMALL*)m_pBuf)->nDirCount;
DWORD index;
for( index = 0; index < m_nDirs; index++)
{
// get the name of the old subdirectory from the cache.
memcpy( m_szDir[index],
((_MEMMAP_HEADER_SMALL*)m_pBuf)->DirArray[index].sDirName,
DIR_NAME_SIZE);
m_szDir[index][DIR_NAME_SIZE] = '\0';
if( GlobalUrlContainers->CreateContentDirWithSecureName( m_szDir[index]) != TRUE)
{
// signal that the directory couldn't be imported and try the next.
m_szDir[index][0] = '\0';
continue;
}
// append the subcontainer names to the appropiate destination and source
//paths.
memcpy( m_szRootPath + m_cbRootPathLength, m_szDir[index], DIR_NAME_SIZE + 1);
memcpy( szSourcePath + cbSourcePathLength, m_szDir[index], DIR_NAME_SIZE + 1);
#ifndef UNIX
if( MoveFile( szSourcePath, m_szRootPath) == 0)
#else
if (!hConstructSubDirs(m_szRootPath) ||
CopyDir(szSourcePath, m_szRootPath))
#endif /* UNIX */
{
// signal that the directory couldn't be imported and try the next.
m_szDir[index][0] = '\0';
continue;
}
}
szSourcePath[ cbSourcePathLength] = '\0';
m_szRootPath[ m_cbRootPathLength] = '\0';
#ifndef UNIX
// The old index file now is full of dead entries,
//so we don't keep it around.
DeleteFile( szFilename);
#endif /* UNIX */
fConstructionSuccessful = TRUE;
exitIE401Construct:
if( fConstructionSuccessful != TRUE)
{
if( m_pBuf != NULL)
delete [] m_pBuf;
m_pBuf = NULL;
}
}
// imports only URLs using Import401Url
BOOL IE401Content::HandleHashElement( ie401::HASH_ITEM* pEntry)
{
// No reserved bits should be set.
INET_ASSERT (!(pEntry->dwHash & HASH_BIT_RESERVED));
if( !(pEntry->dwHash & HASH_BIT_NOTURL)
&& ((ie401::FILEMAP_ENTRY*)(m_pBuf + pEntry->dwOffset))->dwSig == SIG_URL)
{
Import401UrlWithFile( (ie401::URL_FILEMAP_ENTRY*)(m_pBuf + pEntry->dwOffset));
}
// after wrapping above in try-catch block, return FALSE on unhandled exception.
return TRUE;
}
// Extends the default to import files
BOOL IE401Content::Import401UrlWithFile( ie401::URL_FILEMAP_ENTRY* pEntry)
{
BOOL retVal = FALSE;
// don't import Url if it is already in the buffer
if( GetUrlCacheEntryInfo( (LPSTR)((BYTE*)pEntry + pEntry->UrlNameOffset), NULL, 0) == TRUE
|| GetLastError() != ERROR_FILE_NOT_FOUND)
{
goto doneImport401Url;
}
// don't import an URL if its one of those weird registered files.
if( (pEntry->DirIndex == IE401_NOT_A_CACHE_SUBDIRECTORY)
|| (pEntry->CacheEntryType & IE401_EDITED_CACHE_ENTRY))
{
goto doneImport401Url;
}
if( pEntry->FileSize != 0)
{
// don't import Url if it's subdirectory didn't get created
if( m_szDir[pEntry->DirIndex][0] == '\0')
goto doneImport401Url;
// store the new file path in m_szRoot
memcpy( m_szRootPath + m_cbRootPathLength, m_szDir[pEntry->DirIndex], DIR_NAME_SIZE);
m_szRootPath[ m_cbRootPathLength + DIR_NAME_SIZE] = FILENAME_SEPARATOR;
m_szRootPath[ m_cbRootPathLength + DIR_NAME_SIZE + 1] = '\0';
// This may result in truncation of the filename, when the 401 generated filename to
// particularly long, causing the total path to exceed MAX_PATH.
// We won't worry abou this.
StrCatBuff(m_szRootPath,
(CHAR*)pEntry + pEntry->InternalFileNameOffset,
MAX_PATH);
}
if( !CommitUrlCacheEntry(
(LPCSTR)((BYTE*)pEntry + pEntry->UrlNameOffset),
(pEntry->FileSize != 0)
? m_szRootPath : NULL,
*LONGLONG_TO_FILETIME(&pEntry->ExpireTime),
*LONGLONG_TO_FILETIME(&pEntry->LastModifiedTime),
pEntry->CacheEntryType,
pEntry->HeaderInfoOffset != NULL ?
(BYTE*)((BYTE*)pEntry + pEntry->HeaderInfoOffset) : NULL,
pEntry->HeaderInfoSize,
pEntry->FileExtensionOffset != 0 ?
(LPCSTR)((BYTE*)pEntry + pEntry->FileExtensionOffset) : NULL,
NULL))
goto doneImport401Url;
CACHE_ENTRY_INFO cei;
cei.dwStructSize = sizeof(cei);
cei.LastAccessTime = *LONGLONG_TO_FILETIME(&pEntry->LastAccessedTime);
cei.dwHitRate = pEntry->NumAccessed;
cei.ExpireTime = *LONGLONG_TO_FILETIME(&pEntry->ExpireTime);
cei.LastModifiedTime = *LONGLONG_TO_FILETIME(&pEntry->LastModifiedTime);
if( !SetUrlCacheEntryInfo(
(LPCSTR)((BYTE*)pEntry + pEntry->UrlNameOffset),
&cei,
CACHE_ENTRY_ACCTIME_FC | CACHE_ENTRY_HITRATE_FC
| CACHE_ENTRY_EXPTIME_FC | CACHE_ENTRY_MODTIME_FC))
goto doneImport401Url;
retVal = TRUE;
doneImport401Url:
// Remove appended data
m_szRootPath[m_cbRootPathLength] = '\0';
return retVal;
}
//*************************************************************************
//
// Import401Redirects()
//
IE401Redirects::IE401Redirects( IE401Content* pContent)
{
INET_ASSERT( m_pBuf == NULL);
m_pBuf = pContent->m_pBuf;
pContent->m_pBuf = NULL;
}
// import items that are redirects
BOOL IE401Redirects::HandleHashElement( ie401::HASH_ITEM* pEntry)
{
// No reserved bits should be set.
INET_ASSERT (!(pEntry->dwHash & HASH_BIT_RESERVED));
if((pEntry->dwOffset != HASH_END) && ((ie401::FILEMAP_ENTRY*)(m_pBuf + pEntry->dwOffset))->dwSig == SIG_REDIR)
{
Import401Redirect( (ie401::REDIR_FILEMAP_ENTRY*)(m_pBuf + pEntry->dwOffset));
}
// after wrapping above in try-catch block, return FALSE on unhandled exception.
return TRUE;
}
// Imports entries that are redirects
BOOL IE401Redirects::Import401Redirect( ie401::REDIR_FILEMAP_ENTRY* pEntry)
{
LPSTR szTargetUrl = NULL;
//** wrap this one in an exception block, because just one of these guys
//might just try to reference into space.
// pEntry is an entry to a redirect entry, which contains an offset to a hash entry.
// That hash entry contains an offset to the filemap entry of the redirect target.
FILEMAP_ENTRY* pRedirTarget =
(FILEMAP_ENTRY*)(m_pBuf + ((HASH_ITEM*)(m_pBuf + pEntry->dwItemOffset))->dwOffset);
// The filemap entry of the redirect target could be a URL filmap entry or another
//redirect filemap entry. Either way extract the url of that entry as the target url.
switch( pRedirTarget->dwSig)
{
case SIG_REDIR:
szTargetUrl = ((REDIR_FILEMAP_ENTRY*)pRedirTarget)->szUrl;
break;
case SIG_URL:
szTargetUrl = (CHAR*)pRedirTarget + ((URL_FILEMAP_ENTRY*)pRedirTarget)->UrlNameOffset;
break;
default:
return FALSE;
}
return GlobalUrlContainers->CreateContentRedirect( szTargetUrl, pEntry->szUrl);
}
//*************************************************************************
//
// Import401History()
//
// Inside IE401_HIST_ROOT{hHistRoot}, there are some keys that list
//the history containers we want to import. Before we can import those containers,
//we import the Visited: container. This file will be found in the subdirectory of
//the location of the first history subcontainer.
// When we reach a new container, we create it but don't worry about collisions.
//Existing Url entries are never overwritten by the import process.
BOOL Import401History()
{
BOOL retVal = FALSE;
HKEY hHistRoot = (HKEY) INVALID_HANDLE_VALUE;
// get key to root of history information (which is the root of all extensible containers)
if( REGOPENKEYEX( IsPerUserCache() ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE,
IE401_HIST_ROOT, 0, KEY_READ, &hHistRoot)
!= ERROR_SUCCESS)
{
hHistRoot = (HKEY) INVALID_HANDLE_VALUE;
goto doneImport401History;
}
DWORD index; index = 0;
CHAR szContainerName[MAX_PATH];
DWORD cbContainerNameLength;
DWORD dwCacheLimit;
DWORD dwCacheOptions;
CHAR szCachePath[MAX_PATH];
DWORD cbCachePathSize;
CHAR szCachePrefix[MAX_PATH];
// Enumerate through the extensible containers, if they are History containers import them.
// When the first history container is found, its path can be used to locate the Visited:
//container which also must be imported.
while( RegEnumKeyEx( hHistRoot, index++, szContainerName, &(cbContainerNameLength = MAX_PATH),
NULL,NULL,NULL,NULL) == ERROR_SUCCESS)
{
static BOOL fFirstRun = TRUE;
// we can't be sure all the extended containers are history containers.
//This check verifies we only import history containers.
if( StrCmpNI( szContainerName, MSHIST_SZ, sizeof(MSHIST_SZ) - 1) != 0
|| cbContainerNameLength != sizeof(MSHIST_KEY_SZ) - 1)
{
continue;
}
HKEY hHistContainer = (HKEY) INVALID_HANDLE_VALUE;
DWORD dwTemp;
DWORD dwType;
if( REGOPENKEYEX( hHistRoot, szContainerName, 0, KEY_READ, &hHistContainer) != ERROR_SUCCESS)
goto doneImportHistContainer;
if( RegQueryValueEx( hHistContainer, CACHE_LIMIT_SZ, 0, &dwType,
(BYTE*)&dwCacheLimit, &(dwTemp = sizeof(dwCacheLimit))) != ERROR_SUCCESS
|| dwType != REG_DWORD)
{
goto doneImportHistContainer;
}
if( RegQueryValueEx( hHistContainer, CACHE_OPTIONS_SZ, 0, &dwType,
(BYTE*)&dwCacheOptions, &(dwTemp = sizeof(dwCacheOptions))) != ERROR_SUCCESS
|| dwType != REG_DWORD)
{
goto doneImportHistContainer;
}
if( RegQueryValueEx( hHistContainer, CACHE_PATH_SZ, 0, &dwType,
(BYTE*)szCachePath, &(cbCachePathSize = sizeof(szCachePath))) != ERROR_SUCCESS
|| dwType != REG_SZ)
{
goto doneImportHistContainer;
}
if( RegQueryValueEx( hHistContainer, CACHE_PREFIX_SZ, 0, &dwType,
(BYTE*)&szCachePrefix, &(dwTemp = sizeof(szCachePrefix))) != ERROR_SUCCESS
|| dwType != REG_SZ)
{
goto doneImportHistContainer;
}
// After finding the first container, import the Visited: container.
if( fFirstRun == TRUE)
{
// Clip off the path of the history container, and substitute 'index.dat'
//to identify the Visited container. Import the visited container, and
//restore the path to the history container.
CHAR szBuf[sizeof(MSHIST_DIR_SZ)];
LPSTR szMSHIST = szCachePath + cbCachePathSize - sizeof(MSHIST_DIR_SZ);
// ex result: szCachePath:"c:\path\MSHIST011998020119980225\", szMSHIST:"MSHIST011998020119980225\"
memcpy( szBuf, szMSHIST, sizeof(MSHIST_DIR_SZ));
// szBuf:"MSHIST011998020119980225\"
memcpy( szMSHIST, "index.dat", sizeof("index.dat"));
// szMSHIST:"index.dat" --> szCachePath:"c:\path\index.dat"
IE401Visited Visited(szCachePath);
Visited.EnumHashValues();
memcpy( szMSHIST, szBuf, sizeof(MSHIST_DIR_SZ));
// szMSHIST:"MSHIST011998020119980225\" --> szCachePath:"c:\path\MSHIST011998020119980225\"
fFirstRun = FALSE;
}
// we don't pass the old path so that the container is put in the new one.
if( CreateUrlCacheContainer( szContainerName, szCachePrefix, NULL,
dwCacheLimit, 0, dwCacheOptions, NULL, NULL) != TRUE
&& GetLastError() != ERROR_ALREADY_EXISTS)
{
goto doneImportHistContainer;
}
if( cbCachePathSize + (sizeof(INDEX_DAT_SZ) - 1) > MAX_PATH)
goto doneImportHistContainer;
memcpy( szCachePath + cbCachePathSize - 1, INDEX_DAT_SZ, sizeof(INDEX_DAT_SZ));
{
IE401History History( szCachePath);
History.EnumHashValues();
}
doneImportHistContainer:
if( hHistContainer != (HKEY) INVALID_HANDLE_VALUE)
REGCLOSEKEY( hHistContainer);
}
retVal = TRUE;
doneImport401History:
if( hHistRoot != (HKEY) INVALID_HANDLE_VALUE)
REGCLOSEKEY( hHistRoot);
return retVal;
}
//*************************************************************************
//
// Import401Content()
//
BOOL Import401Content()
{
BOOL retVal = FALSE;
HKEY hContentKey = (HKEY) INVALID_HANDLE_VALUE;
CHAR szContentFilename[MAX_PATH];
LPSTR szKeyName = NULL;
if( !GetIE5ContentPath(szContentFilename))
goto doneImport401Content;
// we now have something like 'c:\..\content\content.ie5'
//and we want something like 'c:\..\content\index.dat'
LONG index;
// find the position of the last '\\'
index = lstrlen( szContentFilename);
while( index >= 0 && szContentFilename[index] != FILENAME_SEPARATOR)
index--;
// append an 'index.dat'
memcpy( szContentFilename + index + 1, INDEX_DAT_SZ, sizeof(INDEX_DAT_SZ));
#ifdef UNIX
{
// HACK HACK
//
// we now have something like
// '/home/blah/.microsoft/ie5/TempInternetFiles/index.dat'
// and we want something like
// /home/blah/.microsoft/TempInternetFiles/index.dat
char szSearchStr[] = "ie5/";
char *pszWhere = StrStr(szContentFilename, szSearchStr);
if (pszWhere)
{
memmove(pszWhere, pszWhere+sizeof(szSearchStr)-1,
lstrlen(pszWhere+sizeof(szSearchStr)-1)+1);
}
}
#endif /* UNIX */
{
IE401Content Content(szContentFilename);
if( Content.EnumHashValues() == TRUE)
{
IE401Redirects Redirects( &Content);
Redirects.EnumHashValues();
}
}
doneImport401Content:
if( hContentKey != (HKEY) INVALID_HANDLE_VALUE)
REGCLOSEKEY( hContentKey);
return retVal;
}
//-- end of namespace ie401
}
//--
//
//
// Returns if caches are per user.
//
BOOL IsPerUserCache()
{
BOOL fProfilesEnabled = FALSE;
static BOOL fPerUser = FALSE;
#ifndef UNIX
// Is the OS version Windows 95 or Windows NT?
if (GlobalPlatformType == PLATFORM_TYPE_WIN95)
{
// Operating System is Windows 95.
// Look for special key indicating profiles are enables. If its not found,
//know that profiles aren't enabled.
// Determine if profiles are enabled by OS.
REGISTRY_OBJ roProfilesEnabled(HKEY_LOCAL_MACHINE, PROFILES_ENABLED_VALUE);
if (roProfilesEnabled.GetStatus() == ERROR_SUCCESS)
{
DWORD dwProfilesEnabled = 0;
if( roProfilesEnabled.GetValue(PROFILES_ENABLED, &dwProfilesEnabled) == ERROR_SUCCESS)
{
// Found the registry entry.
fProfilesEnabled = (BOOL) dwProfilesEnabled;
}
}
}
else if (GlobalPlatformType == PLATFORM_TYPE_WINNT)
{
// Profiles always enabled for NT.
fProfilesEnabled = TRUE;
}
#else
fProfilesEnabled = TRUE;
#endif /* UNIX */
// Determine if per user cache is allowed.
REGISTRY_OBJ roProfilesAllowed(HKEY_LOCAL_MACHINE, PRE5_CACHE_KEY);
if( fProfilesEnabled && roProfilesAllowed.GetStatus() == ERROR_SUCCESS)
{
DWORD dwPerUserCache = 0;
if( roProfilesAllowed.GetValue(PROFILES_ENABLED,&dwPerUserCache) == ERROR_SUCCESS)
{
// Found the registry entry. Set g_fPerUserCache to
// TRUE only if profiles are enabled.
fPerUser = ((BOOL) dwPerUserCache);
}
else
{
// No entry. If profiles are enabled, assume they're allowed.
fPerUser = fProfilesEnabled;
}
}
else
{
fPerUser = fProfilesEnabled;
}
return fPerUser;
}