564 lines
14 KiB
C++
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;
|
|
};
|
|
|
|
|
|
|