|
|
#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; }
|