Windows2003-3790/inetcore/wininet/urlcache/contain.hxx
2020-09-30 16:53:55 +02:00

564 lines
14 KiB
C++

/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
contain.hxx
Abstract:
contains class definitions for CONTAINER class objects.
Author:
Madan Appiah (madana) 28-Dec-1994
Environment:
User Mode - Win32
Revision History:
--*/
#ifndef SAFERELEASE
#define SAFERELEASE(p,x) if ((p) != NULL) { (p)->Release(x); (p) = NULL; };
#endif
// so as to easily recognize Extensible prefixes, require them to start with
// a character that is illegal in URLs
#define EXTENSIBLE_FIRST (':')
struct SCORE_ITEM
{
DWORD dwScore; // score of this item
DWORD dwItemOffset; // offset to hash table item
DWORD dwHashValue; // masked value from hash table item
DWORD dwHashOffset; // offset to url entry from hash table item
};
/*++
Class Description:
Class definition that manages the URL objects.
Private Member functions:
Public Member functions:
URL_CONTAINER : constructs an URL container.
~URL_CONTAINER : destructs an URL container.
GetStatus : Retrieves object status.
CleanupUrls : Deletes unused URLs and frees up file system cache space.
DeleteIndex: Deletes all files not in use and attempts to delete index file.
AddUrl : Adds an URL to the container and copies the cache file.
RetrieveUrl : Retrieves an url from the cache.
DeleteUrl : Deletes the specified url from cache.
UnlockUrl : Decrements the reference count.
GetUrlInfo : Gets info of the specified url file.
SetUrlInfo : Sets info of the specified url file.
SetExemptDelta: Sets an exemption on the entry
CreateUniqueFile : Creates a file in the cache path for the incoming url
to store.
GetCacheInfo : Retrieves certain container info.
SetCacheLimit : Sets cache limit value.
DeleteAPendingUrl : Removes and deletes an url from the pending list.
Returns FALSE if the list is empty.
FindNextEntry : Retrieves the next element from the container.
GetCacheSize : return current size of the cache.
--*/
class GroupMgr;
class URL_CONTAINER {
protected:
// This class has one vtable, so there is also one dword of alignment padding.
LONGLONG _CacheStartUpLimit;
DWORD _Status;
MEMMAP_FILE* _UrlObjStorage;
CFileMgr* _FileManager;
LPTSTR _CachePath;
LPTSTR _CachePrefix;
DWORD _CachePrefixLen;
DWORD _CacheEntryType;
LPTSTR _CacheName;
DWORD _CachePathLen;
DWORD _ClusterSizeMinusOne;
DWORD _ClusterSizeMask;
DWORD _FileMapEntrySize;
HANDLE _MutexHandle;
BOOL _fIsInitialized;
DWORD _dwRefCount;
BOOL _fDeletePending;
BOOL _fDeleted;
BOOL _fMarked;
BOOL _fMustLaunchScavenger;
BOOL _fPerUserItem;
DWORD _dwLastReference;
DWORD _dwOptions;
DWORD _dwTaken;
DWORD _dwBytesDownloaded;
DWORD _dwItemsDownloaded;
#ifdef CHECKLOCK_NORMAL
DWORD _dwThreadLocked;
#endif
BOOL SetHeaderFlags(DWORD dwStamp);
DWORD CopyUrlInfo( LPURL_FILEMAP_ENTRY, LPCACHE_ENTRY_INFO*, LPDWORD, DWORD);
DWORD CopyUrlInfoGuard( LPURL_FILEMAP_ENTRY, LPCACHE_ENTRY_INFO*, LPDWORD, DWORD);
void UnlockAllItems (void);
void UnlockItem (URL_FILEMAP_ENTRY* pEntry, HASH_ITEM* pItem);
BOOL UpdateOfflineRedirect (DWORD, LPCSTR, DWORD, LPCSTR);
BOOL DeleteIndex (void);
void CloseContainerFile();
DWORD SetExemptDelta (URL_FILEMAP_ENTRY*, DWORD dwExemptDelta, DWORD dwItemOffset=0);
DWORD DeleteUrlEntry (URL_FILEMAP_ENTRY*, HASH_ITEM* pHash, DWORD dwSig);
DWORD UpdateStickness(URL_FILEMAP_ENTRY*, DWORD dwOp, DWORD dwItemOffset=0);
public:
URL_CONTAINER( LPTSTR CacheName, LPTSTR CachePath, LPTSTR CachePrefix, LONGLONG CacheLimit, DWORD dwOptions );
~URL_CONTAINER( VOID );
DWORD Init();
DWORD GetStatus( VOID )
{
return( _Status );
};
#ifdef CHECKLOCK_PARANOID
void CheckNoLocks(DWORD dwThreadId);
#endif
BOOL LockContainer( BOOL *fMustUnlock );
VOID UnlockContainer( VOID );
BOOL WalkLeakList (void);
DWORD GetLastReference();
BOOL IsVisible();
void Mark(BOOL fMarked);
BOOL GetMarked();
BOOL GetDeleted();
void SetDeleted(BOOL fDeleted);
BOOL GetDeletePending();
void SetDeletePending(BOOL fDeletePending);
void AddRef();
DWORD Release(BOOL fTryToUnmap);
void TryToUnmap(DWORD dwAcceptableRefCount);
DWORD GetOptions();
//
// Internal routines called by the cache management.
//
DWORD CleanupUrls ( DWORD Factor, DWORD dwFilter);
DWORD FixupHandler (DWORD dwFactor, DWORD dwFilter);
BOOL PrefixMatch( LPCSTR UrlName )
{
return (_CachePrefix &&
(strnicmp(_CachePrefix, UrlName, _CachePrefixLen)==0) );
}
#ifdef CHECKLOCK_PARANOID
void CheckUnlocked()
{
INET_ASSERT(_dwTaken==0 || GetCurrentThreadId() != _dwThreadLocked);
}
#endif
LPSTR GetCacheName()
{
return _CacheName;
}
LPSTR GetCachePath()
{
return _CachePath;
}
LPSTR GetCachePrefix()
{
return _CachePrefix;
}
BOOL IsContentContainer()
{
return (_CachePrefix[0] == 0);
}
DWORD GetCachePathLen()
{
return _CachePathLen;
}
DWORD IsInitialized()
{
return _fIsInitialized;
}
BOOL IsPerUserItem()
{
return _fPerUserItem;
}
VOID SetPerUserItem(BOOL fFlag)
{
_fPerUserItem = fFlag;
}
VOID SetCacheSize(LONGLONG dlSize)
{
_UrlObjStorage->SetCacheSize(dlSize);
}
//
// External routines called by the cache APIs.
//
virtual LPSTR GetPrefixMap();
virtual LPSTR GetVolumeLabel();
virtual LPSTR GetVolumeTitle();
virtual DWORD AddUrl(AddUrlArg* args);
virtual DWORD AddIdentityUrl(AddUrlArg* args);
virtual DWORD RetrieveUrl(
LPCSTR UrlName,
LPCACHE_ENTRY_INFO* EntryInfo,
LPDWORD EntryInfoSize,
DWORD dwLookupFlags,
DWORD dwRetrievalFlags);
DWORD DeleteUrl( LPCSTR UrlName );
DWORD UnlockUrl( LPCSTR UrlName );
virtual DWORD GetUrlInfo(
LPCSTR UrlName,
LPCACHE_ENTRY_INFO* ppUrlInfo,
LPDWORD UrlInfoLength,
DWORD dwLookupFlags,
DWORD dwEntryFlags,
DWORD dwRetrievalFlags);
DWORD SetUrlInfo(
LPCSTR UrlName,
LPCACHE_ENTRY_INFO UrlInfo,
DWORD FieldControl);
DWORD SetUrlGroup (LPCSTR lpszUrl, DWORD dwFlags, GROUPID GroupId);
DWORD GetUrlInGroup (LPCSTR lpszUrl, GROUPID* pGroupId, LPDWORD pdwExemptDelta);
DWORD CreateUniqueFile(
LPCSTR UrlName,
DWORD ExpectedSize,
LPCSTR lpszFileExtension,
LPTSTR FileName,
HANDLE *phfHandle,
BOOL fCreateUniqueFile = FALSE);
DWORD RegisterCacheNotify(
HWND hWnd,
UINT uMsg,
GROUPID gid,
DWORD dwFilter);
VOID SendCacheNotification(DWORD dwOpcode)
{
BOOL fUnlock;
LockContainer(&fUnlock);
NotifyCacheChange(dwOpcode, 0);
if (fUnlock) UnlockContainer();
}
VOID SetCacheLimit(LONGLONG CacheLimit )
{
BOOL fUnlock;
LockContainer(&fUnlock);
_UrlObjStorage->SetCacheLimit(CacheLimit);
if (fUnlock) UnlockContainer();
}
LONGLONG GetCacheStartUpLimit()
{
BOOL fUnlock;
LONGLONG llResult;
LockContainer(&fUnlock);
llResult = _CacheStartUpLimit;
if (fUnlock) UnlockContainer();
return llResult;
}
LONGLONG GetCacheLimit()
{
BOOL fUnlock;
LockContainer(&fUnlock);
LONGLONG cbLimit = _UrlObjStorage->GetCacheLimit();
if (fUnlock) UnlockContainer();
return cbLimit;
}
LONGLONG GetCacheSize()
{
BOOL fUnlock;
LockContainer(&fUnlock);
LONGLONG CacheSize = _UrlObjStorage->GetCacheSize();
if (fUnlock) UnlockContainer();
return CacheSize;
}
LONGLONG GetExemptUsage()
{
BOOL fUnlock;
LockContainer(&fUnlock);
LONGLONG ExemptCacheUsage = _UrlObjStorage->GetExemptUsage();
if (fUnlock) UnlockContainer();
return ExemptCacheUsage;
}
VOID GetCacheInfo( LPTSTR CachePath,
LONGLONG *CacheLimit )
{
BOOL fUnlock;
LockContainer(&fUnlock);
*CacheLimit = _UrlObjStorage->GetCacheLimit();
memcpy(CachePath, _CachePath, _CachePathLen);
if (fUnlock) UnlockContainer();
}
DWORD GetInitialFindHandle (void)
{
DWORD dwHandle;
BOOL fUnlock;
LockContainer(&fUnlock);
dwHandle = *_UrlObjStorage->GetPtrToHashTableOffset();
if (fUnlock) UnlockContainer();
return dwHandle;
}
DWORD FindNextEntry(
LPDWORD Handle,
LPCACHE_ENTRY_INFO* lppCacheEntryInfo,
LPDWORD lpCacheEntryInfoSize,
DWORD dwFilter,
GROUPID GroupId,
DWORD dwFlags,
DWORD dwRetrievalFlags);
BOOL SetHeaderData(DWORD nIdx, DWORD dwData)
{
BOOL fRet, fUnlock;
LockContainer(&fUnlock);
fRet = _UrlObjStorage->SetHeaderData(nIdx, dwData);
if (fUnlock) UnlockContainer();
return fRet;
}
BOOL GetHeaderData(DWORD nIdx, LPDWORD pdwData)
{
BOOL fRet, fUnlock;
LockContainer(&fUnlock);
fRet = _UrlObjStorage->GetHeaderData(nIdx, pdwData);
if (fUnlock) UnlockContainer();
return fRet;
}
BOOL IncrementHeaderData(DWORD nIdx, LPDWORD pdwData)
{
BOOL fRet, fUnlock;
LockContainer(&fUnlock);
fRet = _UrlObjStorage->IncrementHeaderData(nIdx, pdwData);
if (fUnlock) UnlockContainer();
return fRet;
}
DWORD AddLeakFile (LPCSTR pszFile);
// Creates a cache directory with a given name to allow existing directories
// to be copied into another cache file.
BOOL CreateDirWithSecureName( LPSTR szDirName)
{
return _FileManager->CreateDirWithSecureName( szDirName);
}
// Creates a redirect from TargetUrl to OriginUrl
BOOL CreateRedirect( LPSTR szTargetUrl, LPSTR szOriginUrl)
{
BOOL retVal = FALSE;
HASH_ITEM* pTargetItem;
if( HashFindItem( szTargetUrl, 0, &pTargetItem) != TRUE)
goto doneCreateRedirect;
if( UpdateOfflineRedirect( OffsetFromPointer(pTargetItem),
szTargetUrl, lstrlen( szTargetUrl),
szOriginUrl) != TRUE)
goto doneCreateRedirect;
retVal = TRUE;
doneCreateRedirect:
return retVal;
}
private:
// hash table wrapper methods
DWORD OffsetFromPointer (LPVOID p)
{
SSIZE_T llDiff = PtrDifference(p, *_UrlObjStorage->GetHeapStart());
#if defined(_AMD64_) || defined(_IA64_)
return GuardedCast(llDiff);
#else
return llDiff;
#endif
}
LPBYTE PointerFromOffset (DWORD dw)
{
return ((LPBYTE) *_UrlObjStorage->GetHeapStart()) + dw;
}
LPURL_FILEMAP_ENTRY HashGetEntry (HASH_ITEM *pItem)
{
INET_ASSERT (pItem->dwHash > HASH_END);
return (URL_FILEMAP_ENTRY*) PointerFromOffset (pItem->dwOffset);
}
void HashSetEntry (HASH_ITEM* pItem, LPBYTE pEntry)
{
pItem->dwOffset = OffsetFromPointer (pEntry);
}
BOOL HashFindItem (LPCSTR pszUrl, DWORD dwLookupFlags, HASH_ITEM** ppItem);
/////////////////////////////////////////////////////////////////////////////
// WARNING: if HASH_*_CREATE set, the file might be grown and remapped //
// so all pointers into the file must be recalculated from their offsets //
/////////////////////////////////////////////////////////////////////////////
PRIVATE HASH_ITEM* IsMatch (HASH_ITEM *pItem, LPCSTR pszKey, DWORD dwFlags);
LPURL_FILEMAP_ENTRY HashFindEntry (LPCSTR pszUrl, DWORD dwLookupFlags = 0)
{
HASH_ITEM *pItem;
if (HashFindItem (pszUrl, dwLookupFlags, &pItem))
return HashGetEntry (pItem);
else
return NULL;
}
void AdjustGroupUsage(GROUP_ENTRY* pGroupEntry, LONGLONG llDelta)
{
if( pGroupEntry && !IsInvalidGroup(pGroupEntry->gid) )
{
if( pGroupEntry->llDiskUsage >= -llDelta )
{
pGroupEntry->llDiskUsage += llDelta;
}
else
{
INET_ASSERT(FALSE); // underflow
pGroupEntry->llDiskUsage = 0;
}
}
}
VOID NotifyCacheChange(DWORD dwOpcode, DWORD dwHOffset)
{
//
// the caller of this method has container locked, so there
// no need to call (Un)LockContain here.
//
DWORD dwFilter = 0;
_UrlObjStorage->GetHeaderData(
CACHE_HEADER_DATA_NOTIFICATION_FILTER, &dwFilter);
if( dwFilter & dwOpcode )
{
DWORD dwHWnd = 0;
DWORD dwUMsg = 0;
_UrlObjStorage->GetHeaderData(
CACHE_HEADER_DATA_NOTIFICATION_HWND, &dwHWnd);
_UrlObjStorage->GetHeaderData(
CACHE_HEADER_DATA_NOTIFICATION_MESG, &dwUMsg);
if( dwHWnd && dwUMsg && IsWindow((HWND)DWORD_PTR(dwHWnd)) )
{
// NOTE: we will not check for msg q overflow
PostMessage(
(HWND)DWORD_PTR(dwHWnd),
(UINT)dwUMsg,
(WPARAM)dwOpcode,
(LPARAM)dwHOffset
);
}
}
}
BOOL IsUrlEntryExemptFromScavenging
(
HASH_ITEM* pItem,
URL_FILEMAP_ENTRY* pEntry,
DWORD dwFilter,
LONGLONG qwGmtTime,
GroupMgr* pgm
);
BOOL ScavengeItem (HASH_ITEM* pItem, BOOL* pfMustUnlock);
void ScavengerDebugSpew (SCORE_ITEM*, LONGLONG*);
friend class GroupMgr;
};