|
|
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name: group.hxx
Abstract:
Manages cache group. Author: Danpo Zhang (DanpoZ) 02-08-98 --*/
#include <cache.hxx>
GroupMgr::GroupMgr() { _pContainer = NULL; }
GroupMgr::~GroupMgr() { if( _pContainer ) { _pContainer->Release(FALSE); } }
BOOL GroupMgr::Init(URL_CONTAINER* pCont) { BOOL fRet = TRUE;
if( pCont ) { _pContainer = pCont; _pContainer->AddRef(); } else { SetLastError(ERROR_INTERNET_INTERNAL_ERROR); fRet = FALSE; }
return fRet; }
DWORD GroupMgr::CreateGroup(DWORD dwFlags, GROUPID* pGID) { INET_ASSERT(_pContainer); INET_ASSERT(pGID);
BOOL fMustUnlock; DWORD dwError; GROUP_ENTRY* pGroupEntry = NULL;
*pGID = 0;
if( !_pContainer->LockContainer(&fMustUnlock) ) { dwError = ERROR_INTERNET_INTERNAL_ERROR; goto exit; }
if( dwFlags & CACHEGROUP_FLAG_GIDONLY ) { // only needs to return GID, no group needs to be created
*pGID = ObtainNewGID(); if( *pGID ) dwError = ERROR_SUCCESS; else dwError = ERROR_INTERNET_INTERNAL_ERROR;
goto exit; }
//
// find the first available entry by using FindEntry()
// passing gid = 0 means looking for empty entry
// passing TRUE means create new page if no entry available
//
dwError = FindEntry(0, &pGroupEntry, TRUE ); if( dwError != ERROR_SUCCESS ) { goto exit; }
// get a new gid
*pGID = ObtainNewGID();
if( *pGID ) { // insert gid into the first available entry
// set the sticky bit for non purgable group
if( dwFlags & CACHEGROUP_FLAG_NONPURGEABLE ) { *pGID = SetStickyBit(*pGID); }
pGroupEntry->gid = *pGID; pGroupEntry->dwGroupFlags = dwFlags; dwError = ERROR_SUCCESS; } exit: if( fMustUnlock ) { _pContainer->UnlockContainer(); }
return dwError; }
DWORD GroupMgr::CreateDefaultGroups() { INET_ASSERT(_pContainer);
BOOL fMustUnlock; DWORD dwError; GROUP_ENTRY* pGroupEntry = NULL; DWORD dwOffsetHead = 0;
if( !_pContainer->LockContainer(&fMustUnlock) ) { dwError = ERROR_INTERNET_INTERNAL_ERROR; goto exit; }
if( GetHeaderData( CACHE_HEADER_DATA_ROOTGROUP_OFFSET, &dwOffsetHead) && dwOffsetHead ) { BOOL fBadHead = FALSE;
// dwOffsetHead may point to a page which has not actually mapped in
if( _pContainer->_UrlObjStorage->IsBadGroupOffset(dwOffsetHead) ) { fBadHead = TRUE; } else { // if offset is too big, invalid
FILEMAP_ENTRY* pFM = NULL;
pFM = (FILEMAP_ENTRY*) (*_pContainer->_UrlObjStorage->GetHeapStart() + dwOffsetHead - sizeof(FILEMAP_ENTRY) ); if(pFM->dwSig != SIG_ALLOC || !pFM->nBlocks ) { fBadHead = TRUE; } } if( fBadHead ) { // dwOffsetHead is invalid, reset!
SetHeaderData(CACHE_HEADER_DATA_ROOTGROUP_OFFSET, 0); } }
// if already created, just return success
dwError = FindEntry(CACHEGROUP_ID_BUILTIN_STICKY, &pGroupEntry, FALSE); if( dwError == ERROR_SUCCESS ) { goto exit; }
//
// not found, need to create new default groups
//
// find the first available entry by using FindEntry()
// passing gid = 0 means looking for empty entry
// passing TRUE means create new page if no entry available
//
dwError = FindEntry(0, &pGroupEntry, TRUE ); if( dwError != ERROR_SUCCESS ) { goto exit; }
// set the sticky bit for non purgable group
pGroupEntry->gid = CACHEGROUP_ID_BUILTIN_STICKY; pGroupEntry->dwGroupFlags = CACHEGROUP_FLAG_NONPURGEABLE; dwError = ERROR_SUCCESS; exit: if( fMustUnlock ) { _pContainer->UnlockContainer(); }
return dwError; }
DWORD GroupMgr::DeleteGroup(GROUPID gid, DWORD dwFlags) { INET_ASSERT(_pContainer); INET_ASSERT(gid);
BOOL fMustUnlock; DWORD dwError; GROUP_ENTRY* pGroupEntry = NULL; GROUP_DATA_ENTRY* pData = NULL; DWORD hUrlFindHandle = 0; URL_FILEMAP_ENTRY* pUrlEntry = 0; DWORD dwFindFilter; HASH_ITEM* pItem = NULL;
if( !_pContainer->LockContainer(&fMustUnlock) ) { dwError = ERROR_INTERNET_INTERNAL_ERROR; goto exit; }
// find the first available entry
dwError = FindEntry(gid, &pGroupEntry, FALSE); if( dwError != ERROR_SUCCESS ) { goto exit; }
// Look for all the url associated with this group
// mark the groupid to 0
hUrlFindHandle = _pContainer->GetInitialFindHandle();
// set up find filter (do not care about cookie/history)
dwFindFilter = URLCACHE_FIND_DEFAULT_FILTER & ~COOKIE_CACHE_ENTRY & ~URLHISTORY_CACHE_ENTRY; //
// loop find all url belongs to this group
// WARNING: this can be slow!
//
do { // next url in this group
pUrlEntry = (URL_FILEMAP_ENTRY*) _pContainer->_UrlObjStorage->FindNextEntry( &hUrlFindHandle, dwFindFilter, gid);
if( pUrlEntry ) { INET_ASSERT(hUrlFindHandle); pItem = (HASH_ITEM*)( (LPBYTE) *_pContainer->_UrlObjStorage->GetHeapStart() + hUrlFindHandle );
if( pItem->HasMultiGroup() ) { //
// examing the group list and remove this group
// from the list
//
DWORD dwNewHeaderOffset = pUrlEntry->dwGroupOffset; DWORD dwGroupEntryOffset = PtrDiff32(pGroupEntry, *_pContainer->_UrlObjStorage->GetHeapStart());
//
// find the to be deleted group entry in the list
// of groups associated with this url, we need to
// fix this by removing the to be dead group from
// the list
//
DWORD Error = RemoveFromGroupList( pUrlEntry->dwGroupOffset, dwGroupEntryOffset, &dwNewHeaderOffset ); //
// found the entry and head offset has been changed
//
if( Error == ERROR_SUCCESS && dwNewHeaderOffset != pUrlEntry->dwGroupOffset ) { pUrlEntry->dwGroupOffset = dwNewHeaderOffset; //
// no more group associated with this url
// let's update the hash flags
//
if( !dwNewHeaderOffset ) { pItem->ClearMultGroup(); pItem->ClearGroup(); } }
// sticky bit
if(!pUrlEntry->dwExemptDelta && IsStickyGroup(gid) ) { //
// unset sticky bit for this url IFF
// 1) we are about to delete the last group of this url
// 2) there is no more sticky group associated with this
// url other than the to be deleted group
//
if( !pUrlEntry->dwGroupOffset || ( pUrlEntry->dwGroupOffset && NoMoreStickyEntryOnList(pUrlEntry->dwGroupOffset))) { _pContainer->UpdateStickness( pUrlEntry, URLCACHE_OP_UNSET_STICKY, hUrlFindHandle ); } } } else { //
// do not move the url entry now, so we just
// need to reset the GroupOffset and re-exam the
// stick bit
//
pUrlEntry->dwGroupOffset = 0;
// sticky bit
if(!pUrlEntry->dwExemptDelta && IsStickyGroup(gid) ) {
_pContainer->UpdateStickness( pUrlEntry, URLCACHE_OP_UNSET_STICKY, hUrlFindHandle ); }
}
if( dwFlags & CACHEGROUP_FLAG_FLUSHURL_ONDELETE) { //
// Container's DeleteUrlEntry method takes two
// param, the url entry and hash item.
// The hUrlFindHandle actually contains the
// offset of the Hash Item, so we can get
// the hash item from there.
//
// if this url belongs to other groups,
// do not delete it
if( !pItem->HasMultiGroup() ) { _pContainer->DeleteUrlEntry(pUrlEntry, pItem, SIG_DELETE); } }
} // find next url
} while( pUrlEntry); // if data entry exists, we should free them as well
if( pGroupEntry->dwGroupNameOffset ) { dwError = FindDataEntry(pGroupEntry, &pData, FALSE); if( dwError == ERROR_SUCCESS ) { FreeDataEntry(pData); } }
memset(pGroupEntry, 0, sizeof(GROUP_ENTRY) ); dwError = ERROR_SUCCESS;
exit: if( fMustUnlock ) { _pContainer->UnlockContainer(); }
return dwError; }
DWORD GroupMgr::GetGroup( GROUPID gid, DWORD dwAttrib, INTERNET_CACHE_GROUP_INFOA* pOutGroupInfo, DWORD* pdwOutGroupInfoSize ) { INET_ASSERT(_pContainer); INET_ASSERT(gid && pOutGroupInfo && pdwOutGroupInfoSize);
BOOL fMustUnlock; DWORD dwError; GROUP_ENTRY* pGroupEntry = NULL;
if( !_pContainer->LockContainer(&fMustUnlock) ) { dwError = ERROR_INTERNET_INTERNAL_ERROR; goto exit; }
*pdwOutGroupInfoSize = 0;
// find the entry
dwError = FindEntry(gid, &pGroupEntry, FALSE); if( dwError != ERROR_SUCCESS ) { goto exit; }
// init out param
memset(pOutGroupInfo, 0, sizeof(INTERNET_CACHE_GROUP_INFOA) );
// copy over GROUP_ENTRY -> GROUP_INFO
Translate( dwAttrib, pOutGroupInfo, pGroupEntry, GROUP_ENTRY_TO_INFO, pdwOutGroupInfoSize ); dwError = ERROR_SUCCESS;
exit: if( fMustUnlock ) { _pContainer->UnlockContainer(); }
return dwError; }
DWORD GroupMgr::SetGroup( GROUPID gid, DWORD dwAttrib, INTERNET_CACHE_GROUP_INFOA* pGroupInfo ) { INET_ASSERT(_pContainer); INET_ASSERT(pGroupInfo && gid);
BOOL fMustUnlock; DWORD dwError; GROUP_ENTRY* pGroupEntry;
if( !_pContainer->LockContainer(&fMustUnlock) ) { dwError = GetLastError(); goto Cleanup; }
pGroupEntry = NULL;
INET_ASSERT(pGroupInfo);
if( dwAttrib & ~(CACHEGROUP_READWRITE_MASK) ) { //
// read only fields are being requested
//
dwError = ERROR_INVALID_PARAMETER; goto Cleanup; }
if( (dwAttrib & CACHEGROUP_ATTRIBUTE_GROUPNAME) && (strlen(pGroupInfo->szGroupName) >= GROUPNAME_MAX_LENGTH ) ) { //
// name too long, exceed the buffer limit
//
dwError = ERROR_INVALID_PARAMETER; goto Cleanup; }
// find the entry
dwError = FindEntry(gid, &pGroupEntry, FALSE); if( dwError != ERROR_SUCCESS ) { goto Cleanup; }
// copy over GROUP_INFO -> GROUP_ENTRY
Translate( dwAttrib, pGroupInfo, pGroupEntry, GROUP_INFO_TO_ENTRY, 0 ); dwError = ERROR_SUCCESS; Cleanup: if( fMustUnlock ) { _pContainer->UnlockContainer(); }
return dwError; }
DWORD GroupMgr::GetNextGroup( DWORD* pdwLastItemOffset, GROUPID* pOutGroupId ) { INET_ASSERT(_pContainer); INET_ASSERT(pOutGroupId);
BOOL fMustUnlock; BOOL fEndOfGroups; GROUP_ENTRY* pGroupEntry; DWORD dwNewOffset; DWORD dwError;
if( !_pContainer->LockContainer(&fMustUnlock) ) { dwError = ERROR_INTERNET_INTERNAL_ERROR; fEndOfGroups = TRUE; goto Cleanup; }
pGroupEntry = NULL; dwNewOffset = 0; fEndOfGroups = FALSE;
if( *pdwLastItemOffset == 0 ) { // get root
dwError = FindRootEntry(&pGroupEntry, FALSE ); if( dwError != ERROR_SUCCESS ) { //
// new find and we can not get the root entry
// this means there are no group at all.
//
fEndOfGroups = TRUE; goto Cleanup; } } // IF: no previous offset, this is a new Find
else if( *pdwLastItemOffset == OFFSET_NO_MORE_GROUP ) { // this group of search has completed already
fEndOfGroups = TRUE; dwError = ERROR_FILE_NOT_FOUND; goto Cleanup;
} // ELSE IF: previous FindNext has already reached the end of the groups
else { //
// use the offset to jump to the last returned item's entry
//
pGroupEntry = (GROUP_ENTRY*) (*_pContainer->_UrlObjStorage->GetHeapStart() + *pdwLastItemOffset); //
// one step forward
//
INET_ASSERT(pGroupEntry); // can't be null
INET_ASSERT( !IsIndexToNewPage(pGroupEntry) ); // can't be index item
pGroupEntry++;
} // ELSE: walk to the item which has been returned by previous FindNext()
// loop for next entry
while(pGroupEntry) { //
// if this entry is the last one of the page
// it contains offset pointing to the next page
//
if( IsIndexToNewPage(pGroupEntry) ) { //
// BUGBUG
// we currently use dwFlags to indicating if
// this is pointing to the next offset
//
if( pGroupEntry->dwGroupFlags ) { //
// walk to next page
//
pGroupEntry = (GROUP_ENTRY*) ( *_pContainer->_UrlObjStorage->GetHeapStart() + pGroupEntry->dwGroupFlags ); } // IF: index entry point to next page
else { //
// we are done
//
fEndOfGroups = TRUE; dwError = ERROR_FILE_NOT_FOUND; break;
} // ELSE: index page contains nothing (this is the last page)
} // special case: current entry is the index(point to next page)
//
// using gid to test if the entry is empty, if not,
// walk to the next entry
//
if( !pGroupEntry->gid ) { pGroupEntry++; } else { break; }
} // while(pGroupEntry)
Cleanup: // update LastItemOffset
if (!fEndOfGroups && pGroupEntry) { LPBYTE lpbBase = *_pContainer->_UrlObjStorage->GetHeapStart(); dwNewOffset = PtrDiff32(pGroupEntry, lpbBase); *pdwLastItemOffset = dwNewOffset;
// copy over GROUP_ENTRY -> GROUP_INFO
*pOutGroupId = pGroupEntry->gid; dwError = ERROR_SUCCESS;
} // IF: find the item
else { *pdwLastItemOffset = OFFSET_NO_MORE_GROUP; dwError = ERROR_FILE_NOT_FOUND; } // ELSE: not find
if( fMustUnlock ) { _pContainer->UnlockContainer(); }
return dwError; }
DWORD GroupMgr::FindRootEntry( GROUP_ENTRY** ppOut, // OUT: first empty entry
BOOL fCreate // allocate new page if needed
) { INET_ASSERT(ppOut); *ppOut = NULL; GROUPS_ALLOC_FILEMAP_ENTRY* pPage = NULL; DWORD dwError; DWORD dwOffsetToRootEntry = 0;
// get base offset
if( GetHeaderData( CACHE_HEADER_DATA_ROOTGROUP_OFFSET, &dwOffsetToRootEntry)) { if( !dwOffsetToRootEntry && fCreate ) { dwError = CreateNewPage(&dwOffsetToRootEntry, TRUE);
if( dwError != ERROR_SUCCESS) { goto Cleanup; } } else if( !dwOffsetToRootEntry && !fCreate ) { //
// there is no offset infomation on the mem file
// however, the flag says do not create a new page
// failure is the only option here
//
dwError = ERROR_FILE_NOT_FOUND; goto Cleanup; }
} // IF: retrieve base offset
else { dwError = ERROR_INTERNET_INTERNAL_ERROR; goto Cleanup;
} // ELSE: failed to get base offset
//
// At this point, we should either:
// 1. retrieved valid dwOffsetToRootEntry or
// 2. get the new dwOffsetToRootEntry via CreateNewPage() call
//
INET_ASSERT( dwOffsetToRootEntry ); *ppOut = (GROUP_ENTRY*) ( *_pContainer->_UrlObjStorage->GetHeapStart() + dwOffsetToRootEntry); dwError = ERROR_SUCCESS;
Cleanup: return dwError; }
DWORD GroupMgr::FindEntry( GROUPID gid, // gid, 0 means find first empty seat
GROUP_ENTRY** ppOut, // OUT: entry with gid specified
BOOL fCreate // allocate new page if needed
// (applied for searching empty seat only)
) { INET_ASSERT(ppOut);
// fCreate can only be associated with gid == 0
INET_ASSERT( (fCreate && !gid ) || (!fCreate && gid ) );
GROUP_ENTRY* pGroupEntry = NULL; DWORD dwError;
// get Root Entry
dwError = FindRootEntry(&pGroupEntry, fCreate); if( dwError != ERROR_SUCCESS ) { dwError = ERROR_INTERNET_INTERNAL_ERROR; goto Cleanup; } // failed to get the root entry
INET_ASSERT(pGroupEntry); // pGroupEntry should be available now
while(1) { // special case for end of this page
if( IsIndexToNewPage(pGroupEntry) ) { //
// BUGBUG
// we currently use the dwFlags to indicating
// if this is pointing to the next offset
//
if( pGroupEntry->dwGroupFlags ) { // walk to next page
pGroupEntry = (GROUP_ENTRY*) ( *_pContainer->_UrlObjStorage->GetHeapStart() + pGroupEntry->dwGroupFlags );
} // IF: index entry points to next page
else if( fCreate) { //////////////////////////////////////////////////////////////////
// BEGIN WARNING: The file might be grown and remapped, so all //
// pointers into the file before this point may be invalidated. //
//////////////////////////////////////////////////////////////////
DWORD dwOffsetToFirstEntry = 0; LPBYTE lpbBase = NULL;
// remember the old offset for pGroupEntry
DWORD_PTR dwpEntryOffset = PtrDifference(pGroupEntry, *_pContainer->_UrlObjStorage->GetHeapStart());
// create new page!
dwError = CreateNewPage(&dwOffsetToFirstEntry, FALSE); if( dwError != ERROR_SUCCESS ) { goto Cleanup; }
// recalculate pGroupEntry using the offset remembered
lpbBase = *_pContainer->_UrlObjStorage->GetHeapStart(); pGroupEntry = (GROUP_ENTRY*)(lpbBase + dwpEntryOffset);
//////////////////////////////////////////////////////////////////
// END WARNING: The file might be grown and remapped, so all //
// pointers into the file before this point may be invalidated. //
//////////////////////////////////////////////////////////////////
//
// pGroupEntry currently is the index item, insert
// the offset of the first item to the newly created page
//
pGroupEntry->dwGroupFlags = dwOffsetToFirstEntry;
// walk to the new page
pGroupEntry = (GROUP_ENTRY*)(lpbBase + dwOffsetToFirstEntry);
} // ELSE IF: index entry not point to new page, fCreate is
// set, a new page is being created
else { // this is the end of all groups, item still not found,
dwError = ERROR_FILE_NOT_FOUND; break;
} // ELSE: index entry not point to new page, fCreate not set
} // IF: this entry is an index entry
//
// now pGroupEntry must point to a normal group entry
//
INET_ASSERT( !IsIndexToNewPage(pGroupEntry) );
if( pGroupEntry->gid != gid ) { // not found, walk to next entry
pGroupEntry++; } else { // found entry
dwError = ERROR_SUCCESS; break; }
} // WHILE: (loop over all page)
Cleanup: if( dwError == ERROR_SUCCESS ) { *ppOut = pGroupEntry; } else { *ppOut = NULL; }
return dwError; }
DWORD GroupMgr::CreateNewPage(DWORD* dwOffsetToFirstEntry, BOOL fIsFirstPage) { DWORD dwError; GROUPS_ALLOC_FILEMAP_ENTRY* pPage = NULL; DWORD cbSize = sizeof(GROUPS_ALLOC_FILEMAP_ENTRY);
pPage = (GROUPS_ALLOC_FILEMAP_ENTRY*) _pContainer->_UrlObjStorage->AllocateEntry(cbSize);
if( pPage ) { // clean up allocated page
cbSize = PAGE_SIZE_FOR_GROUPS; memset(pPage->pGroupBlock, 0, cbSize );
// calculate the group base offset
LPBYTE lpbBase = *_pContainer->_UrlObjStorage->GetHeapStart();
*dwOffsetToFirstEntry = PtrDiff32(pPage->pGroupBlock, lpbBase);
//
// mark the last entry as index to next page
// (gid == GID_INDEX_TO_NEXT_PAGE) is the mark,
// the actual offset is stored at dwGroupFlags field
//
GROUP_ENTRY* pEnd = (GROUP_ENTRY*) pPage->pGroupBlock; pEnd = pEnd + (GROUPS_PER_PAGE - 1); pEnd->gid = GID_INDEX_TO_NEXT_PAGE;
if( fIsFirstPage ) { //
// for first page, we would have to set the offset
// back to the CacheHeader
//
if( !SetHeaderData( CACHE_HEADER_DATA_ROOTGROUP_OFFSET, *dwOffsetToFirstEntry)) { // free allocated page
_pContainer->_UrlObjStorage->FreeEntry(pPage); // set error and go
*dwOffsetToFirstEntry = 0; dwError = ERROR_INTERNET_INTERNAL_ERROR; goto Cleanup;
} // IF: failed to set the offset
}
// return the offset to the first entry of the new page
dwError = ERROR_SUCCESS;
} // IF: Allocate new page succeed
else { dwError = ERROR_NOT_ENOUGH_MEMORY; } // ELSE: failed to allocate new page
Cleanup: return dwError; }
GROUPID GroupMgr::ObtainNewGID() { SYSTEMTIME st; DWORD dwC[2] = {0, 0}; GROUPID gid = 0;
// get counter from index file
if( GetHeaderData(CACHE_HEADER_DATA_GID_LOW, &dwC[0]) && GetHeaderData(CACHE_HEADER_DATA_GID_HIGH, &dwC[1]) ) { if( !dwC[0] && !dwC[1] ) { // need to get the current system time
GetSystemTime( &st ); SystemTimeToFileTime(&st, (FILETIME*)dwC);
} // IF: counter not initialized
else { // increment
if( dwC[0] != 0xffffffff ) { dwC[0] ++; } else { dwC[0] = 0; dwC[1] ++; } } // ELSE: counter initialized
// send data back to cache
if( SetHeaderData(CACHE_HEADER_DATA_GID_LOW, dwC[0] ) && SetHeaderData(CACHE_HEADER_DATA_GID_HIGH, dwC[1] ) ) { //memcpy(&gid, dwC, sizeof(GROUPID) );
gid = *((GROUPID *)dwC); } } // apply the mask to newly created gid
// the first 4 bits are reserved (one bit is used for stickness)
return (gid & GID_MASK); }
BOOL GroupMgr::Translate( DWORD dwAttrib, INTERNET_CACHE_GROUP_INFOA* pGroupInfo, GROUP_ENTRY* pGroupEntry, DWORD dwFlag, DWORD* pdwSize ) { INET_ASSERT(pGroupInfo && pGroupEntry); BOOL fRet = TRUE; GROUP_DATA_ENTRY* pData = NULL; DWORD dwError;
if( dwFlag == GROUP_ENTRY_TO_INFO ) { INET_ASSERT(pdwSize);
// clear
memset(pGroupInfo, 0, sizeof(INTERNET_CACHE_GROUP_INFOA) ); *pdwSize = 0;
// basic entries
if( dwAttrib & CACHEGROUP_ATTRIBUTE_BASIC ) { pGroupInfo->dwGroupSize = sizeof(INTERNET_CACHE_GROUP_INFOA); pGroupInfo->dwGroupFlags = pGroupEntry->dwGroupFlags; pGroupInfo->dwGroupType = pGroupEntry->dwGroupType; pGroupInfo->dwDiskUsage = (DWORD)(pGroupEntry->llDiskUsage / 1024); pGroupInfo->dwDiskQuota = pGroupEntry->dwDiskQuota; } // user friendly name
if( ( (dwAttrib & CACHEGROUP_ATTRIBUTE_GROUPNAME) | (dwAttrib & CACHEGROUP_ATTRIBUTE_STORAGE ) ) && pGroupEntry->dwGroupNameOffset ) { dwError = FindDataEntry(pGroupEntry, &pData, FALSE); if( dwError != ERROR_SUCCESS ) { fRet = FALSE; } else { DWORD dwLen = strlen(pData->szName) + 1; INET_ASSERT( dwLen > GROUPNAME_MAX_LENGTH );
memcpy( pGroupInfo->szGroupName, pData->szName, dwLen );
memcpy( pGroupInfo->dwOwnerStorage, pData->dwOwnerStorage, sizeof(DWORD) * GROUP_OWNER_STORAGE_SIZE ); } }
// set size
*pdwSize = sizeof(INTERNET_CACHE_GROUP_INFOA); }
else if( dwFlag == GROUP_INFO_TO_ENTRY ) { // copy
if( dwAttrib & CACHEGROUP_ATTRIBUTE_FLAG ) { pGroupEntry->dwGroupFlags = pGroupInfo->dwGroupFlags; }
if( dwAttrib & CACHEGROUP_ATTRIBUTE_TYPE ) { pGroupEntry->dwGroupType = pGroupInfo->dwGroupType; }
if( dwAttrib & CACHEGROUP_ATTRIBUTE_QUOTA ) { pGroupEntry->dwDiskQuota = pGroupInfo->dwDiskQuota; }
if( (dwAttrib & CACHEGROUP_ATTRIBUTE_GROUPNAME) | (dwAttrib & CACHEGROUP_ATTRIBUTE_STORAGE ) ) {
dwError = FindDataEntry(pGroupEntry, &pData, TRUE); if( dwError != ERROR_SUCCESS ) { fRet = FALSE; } else { if( dwAttrib & CACHEGROUP_ATTRIBUTE_GROUPNAME ) { DWORD dwLen = strlen(pGroupInfo->szGroupName) + 1; INET_ASSERT(dwLen > GROUPNAME_MAX_LENGTH);
memcpy( pData->szName, pGroupInfo->szGroupName, dwLen ); }
if( dwAttrib & CACHEGROUP_ATTRIBUTE_STORAGE ) { memcpy( pData->dwOwnerStorage, pGroupInfo->dwOwnerStorage, sizeof(DWORD) * GROUP_OWNER_STORAGE_SIZE ); }
// BUGBUG
// if both fields are set to be empty, we should free
// the allocated data itam
} } }
else { fRet = FALSE; } return fRet; }
BOOL GroupMgr::IsPageEmpty(GROUP_ENTRY* pHead) { BOOL fRet = FALSE;
GROUP_ENTRY* pGroupEntry = pHead; for( int i = 0; i < (GROUPS_PER_PAGE - 1); i ++) { if( pGroupEntry->gid ) { break; } else { pGroupEntry++; } }
// there is no item found on this page
if( !pGroupEntry->gid && i == GROUPS_PER_PAGE - 1 ) { fRet = TRUE; }
return fRet; }
BOOL GroupMgr::IsLastPage(GROUP_ENTRY* pHead) { BOOL fRet = FALSE;
GROUP_ENTRY* pEnd = NULL;
// jump to last item
pEnd = pHead + GROUPS_PER_PAGE;
//
// the gid has to be marked as GID_INDEX_TO_NEXT_PAGE
// for index entry, and if the dwGroupFlags is 0,
// that means we are not pointing to any
// other page, this is the last page indeed.
//
if( pEnd->gid == GID_INDEX_TO_NEXT_PAGE && !pEnd->dwGroupFlags ) { fRet = TRUE; }
return fRet; }
BOOL GroupMgr::FreeEmptyPages(DWORD dwFlags) { INET_ASSERT(_pContainer); BOOL fMustUnlock;
BOOL fRet = TRUE; GROUP_ENTRY* pHead = NULL; GROUP_ENTRY* pPrevHead = NULL; GROUP_ENTRY* pEnd = NULL; GROUP_ENTRY* pTobeDeleted = NULL; BOOL fFirstPage = TRUE;
if( !_pContainer->LockContainer(&fMustUnlock) ) { fRet = FALSE; goto Cleanup; }
// BUGBUG FindRootEntry changed the return code, check for dwError
if( FindRootEntry(&pHead, FALSE ) ) { pPrevHead = pHead; while(pHead) { pTobeDeleted = NULL;
if( IsPageEmpty(pHead) ) { pTobeDeleted = pHead;
//
// find the offset of the next page
// 0 which means the current page is the last one
//
DWORD dwOffsetNextPage = 0; pEnd = pHead + GROUPS_PER_PAGE; dwOffsetNextPage = pEnd->dwGroupFlags;
//
// if the first page is to be deleted, we have to
// update the offset which points to the next page
//
if( fFirstPage) { if( !SetHeaderData( CACHE_HEADER_DATA_ROOTGROUP_OFFSET, dwOffsetNextPage)) { fRet = FALSE; goto Cleanup; } } else { //
// Link Prev page to Next page
//
GROUP_ENTRY* pPrevEnd = pPrevHead + GROUPS_PER_PAGE; pPrevEnd->dwGroupFlags = dwOffsetNextPage; } }
//
// update pHead make it point to the next page
//
if( !IsLastPage(pHead) ) { // remember pPrev
pPrevHead = pHead;
// walk to next page
pEnd = pHead + GROUPS_PER_PAGE; pHead = (GROUP_ENTRY*) ( *_pContainer->_UrlObjStorage->GetHeapStart() + pEnd->dwGroupFlags );
// not first page anymore
fFirstPage = FALSE; } else { // this is the last page
pHead = NULL; }
//
// free the tobe deleted page
//
if( pTobeDeleted ) { GROUPS_ALLOC_FILEMAP_ENTRY* pPage = NULL; pPage = (GROUPS_ALLOC_FILEMAP_ENTRY*) ((LPBYTE)pTobeDeleted - sizeof(FILEMAP_ENTRY));
_pContainer->_UrlObjStorage->FreeEntry(pPage); } } }
Cleanup: if( fMustUnlock ) { _pContainer->UnlockContainer(); } return fRet; }
DWORD GroupMgr::FindDataEntry( GROUP_ENTRY* pGroupEntry, GROUP_DATA_ENTRY** pOutData, BOOL fCreate ) { INET_ASSERT(_pContainer); INET_ASSERT(pGroupEntry && pOutData ); *pOutData = NULL;
BOOL fMustUnlock; DWORD dwError; LPBYTE lpbBase = NULL;
if( !_pContainer->LockContainer(&fMustUnlock) ) { dwError = ERROR_INTERNET_INTERNAL_ERROR; goto exit; }
if( pGroupEntry->dwGroupNameOffset ) { lpbBase = *_pContainer->_UrlObjStorage->GetHeapStart(); *pOutData = (GROUP_DATA_ENTRY*) (lpbBase + pGroupEntry->dwGroupNameOffset); dwError = ERROR_SUCCESS; }
else if( fCreate) { //////////////////////////////////////////////////////////////////
// BEGIN WARNING: The file might be grown and remapped, so all //
// pointers into the file before this point may be invalidated. //
//////////////////////////////////////////////////////////////////
// remember the old offset for pGroupEntry
DWORD_PTR dwpEntryOffset = PtrDifference(pGroupEntry, *_pContainer->_UrlObjStorage->GetHeapStart());
// create new data entry
*pOutData = GetHeadDataEntry(TRUE); if( *pOutData ) { //
// re-calc pGroupEntry
//
lpbBase = (LPBYTE) *_pContainer->_UrlObjStorage->GetHeapStart(); pGroupEntry = (GROUP_ENTRY*)(lpbBase + dwpEntryOffset);
//
// set entry's filename offset field
//
pGroupEntry->dwGroupNameOffset = PtrDiff32(*pOutData, lpbBase);
// succeed
dwError = ERROR_SUCCESS; } else { dwError = ERROR_INTERNET_INTERNAL_ERROR; } //////////////////////////////////////////////////////////////////
// END WARNING: The file might be grown and remapped, so all //
// pointers into the file before this point may be invalidated. //
//////////////////////////////////////////////////////////////////
}
else { dwError = ERROR_FILE_NOT_FOUND; }
exit: if( fMustUnlock ) { _pContainer->UnlockContainer(); }
if( fCreate && (dwError == ERROR_SUCCESS) ) { // for new item, it's nice to mark the next link to 0
(*pOutData)->dwOffsetNext = 0; } return dwError; }
VOID GroupMgr::FreeDataEntry(GROUP_DATA_ENTRY* pDataEntry) { // get the head entry
GROUP_ENTRY* pGroupEntry = NULL; DWORD dwError = FindRootEntry(&pGroupEntry, FALSE ); if( dwError != ERROR_SUCCESS ) { return; }
//
// walk to the index item whose dwGroupNameOffset
// contains offset the the head of free list
//
pGroupEntry += (GROUPS_PER_PAGE - 1); INET_ASSERT( pGroupEntry->gid == GID_INDEX_TO_NEXT_PAGE);
// memset the freed data entry
memset(pDataEntry, 0, sizeof(GROUP_DATA_ENTRY) );
// make data item's next link points to current head
pDataEntry->dwOffsetNext = pGroupEntry->dwGroupNameOffset;
// make the current head to be the just freed item's offset
LPBYTE lpbBase = *_pContainer->_UrlObjStorage->GetHeapStart(); pGroupEntry->dwGroupNameOffset = PtrDiff32(pDataEntry, lpbBase); }
LPGROUP_DATA_ENTRY GroupMgr::GetHeadDataEntry(BOOL fCreate) { GROUP_DATA_ENTRY* pDataEntry = NULL; GROUP_ENTRY* pGroupEntry = NULL; LPBYTE lpbBase = NULL;
// get the head entry
DWORD dwError = FindRootEntry(&pGroupEntry, FALSE ); if( dwError != ERROR_SUCCESS ) { goto exit; }
// walk to the index item
pGroupEntry += (GROUPS_PER_PAGE - 1); INET_ASSERT( pGroupEntry->gid == GID_INDEX_TO_NEXT_PAGE);
// the dwGroupNameOffset contains offset the the head of free list
if( pGroupEntry->dwGroupNameOffset) { // get the head
lpbBase = (LPBYTE) *_pContainer->_UrlObjStorage->GetHeapStart(); pDataEntry = (GROUP_DATA_ENTRY*) (lpbBase + pGroupEntry->dwGroupNameOffset);
// reset head to next one
pGroupEntry->dwGroupNameOffset = pDataEntry->dwOffsetNext; }
else if( fCreate ) { //////////////////////////////////////////////////////////////////
// BEGIN WARNING: The file might be grown and remapped, so all //
// pointers into the file before this point may be invalidated. //
//////////////////////////////////////////////////////////////////
// remember the old offset for pGroupEntry
DWORD_PTR dwpEntryOffset = PtrDifference(pGroupEntry, *_pContainer->_UrlObjStorage->GetHeapStart());
// create a new page
GROUPS_ALLOC_FILEMAP_ENTRY* pPage = NULL; DWORD cbSize = sizeof(GROUPS_ALLOC_FILEMAP_ENTRY);
pPage = (GROUPS_ALLOC_FILEMAP_ENTRY*) _pContainer->_UrlObjStorage->AllocateEntry(cbSize);
if( !pPage ) { goto exit; } // memset
memset(pPage->pGroupBlock, 0, PAGE_SIZE_FOR_GROUPS);
lpbBase = (LPBYTE) *_pContainer->_UrlObjStorage->GetHeapStart(); GROUP_DATA_ENTRY* pHead = (GROUP_DATA_ENTRY*)pPage->pGroupBlock; pDataEntry = pHead;
// init list on the newly created page
for(int i = 0; i < GROUPS_DATA_PER_PAGE - 1; i++) { // point to next offset
GROUP_DATA_ENTRY* pNext = pHead + 1; pHead->dwOffsetNext = PtrDiff32(pNext, lpbBase); pHead = pNext; }
//
// pGroupEntry needs to be re-calc!
//
pGroupEntry = (GROUP_ENTRY*)(lpbBase + dwpEntryOffset);
//
// pGroupEntry currently is the index entry of the first
// page, it's dwGroupNameOffset field points the head of
// the list of a free group data entry
//
pGroupEntry->dwGroupNameOffset = pDataEntry->dwOffsetNext;
//////////////////////////////////////////////////////////////////
// END WARNING: The file might be grown and remapped, so all //
// pointers into the file before this point may be invalidated. //
//////////////////////////////////////////////////////////////////
}
else { goto exit; } exit: return pDataEntry; }
DWORD GroupMgr::GetOffsetFromList(DWORD dwHeadOffset, GROUPID gid, DWORD* pdwOffset) { DWORD dwError; LIST_GROUP_ENTRY* pListGroup = NULL; GROUP_ENTRY* pGroupEntry = NULL; *pdwOffset = 0;
pListGroup = _pContainer->_UrlObjStorage->ValidateListGroupOffset(dwHeadOffset); if( !pListGroup ) { dwError = ERROR_FILE_NOT_FOUND; goto Cleanup; }
while(1) { if(!_pContainer->_UrlObjStorage->IsBadGroupOffset(pListGroup->dwGroupOffset)) { pGroupEntry = (GROUP_ENTRY*) ( *_pContainer->_UrlObjStorage->GetHeapStart() + pListGroup->dwGroupOffset ); } else { dwError = ERROR_INTERNET_INTERNAL_ERROR; goto Cleanup; }
if( pGroupEntry && pGroupEntry->gid == gid ) { *pdwOffset = pListGroup->dwGroupOffset; break; }
// end of list, not found
if( !pListGroup->dwNext ) { dwError = ERROR_FILE_NOT_FOUND; break; }
// walk to next
pListGroup = _pContainer->_UrlObjStorage->ValidateListGroupOffset( pListGroup->dwNext);
if( !pListGroup ) { dwError = ERROR_FILE_NOT_FOUND; goto Cleanup; } }
if( *pdwOffset ) { dwError = ERROR_SUCCESS; } else { dwError = ERROR_FILE_NOT_FOUND; }
Cleanup: return dwError; }
DWORD GroupMgr::CreateNewGroupList(DWORD* pdwHeadOffset) { DWORD dwError; // Find empty slot
*pdwHeadOffset = 0; dwError = FindEmptySlotInListPage(pdwHeadOffset); if( ERROR_SUCCESS != dwError ) { goto Cleanup; }
Cleanup: return dwError; }
DWORD GroupMgr::AddToGroupList(DWORD dwHeadOffset, DWORD dwOffset) { DWORD dwError; DWORD dwEmptySlot; LIST_GROUP_ENTRY* pListGroup = NULL; LIST_GROUP_ENTRY* pListGroupEmpty = NULL;
// if the item already on the list, return success
if( IsGroupOnList(dwHeadOffset, dwOffset) ) { dwError = ERROR_SUCCESS; goto Cleanup; }
pListGroup = _pContainer->_UrlObjStorage->ValidateListGroupOffset(dwHeadOffset); if( !pListGroup ) { dwError = ERROR_INTERNET_INTERNAL_ERROR; goto Cleanup; }
if( !pListGroup->dwGroupOffset ) { // list is empty, just need to fill up the Head
pListGroup->dwGroupOffset = dwOffset; } else { // List is not empty, we have to walk to end of the list
// also need to get another empty slot
//////////////////////////////////////////////////////////////////
// BEGIN WARNING: The file might be grown and remapped, so all //
// pointers into the file before this point may be invalidated. //
//////////////////////////////////////////////////////////////////
// remember the old offset for pListGroup
DWORD_PTR dwpListGroupOffset = PtrDifference(pListGroup, *_pContainer->_UrlObjStorage->GetHeapStart());
// find empty slot
dwError = FindEmptySlotInListPage(&dwEmptySlot); if( ERROR_SUCCESS != dwError ) { goto Cleanup; }
// recalculate pListGroup using the offset remembered
LPBYTE lpbBase = *_pContainer->_UrlObjStorage->GetHeapStart(); pListGroup = (LIST_GROUP_ENTRY*)(lpbBase + dwpListGroupOffset);
//////////////////////////////////////////////////////////////////
// END WARNING: The file might be grown and remapped, so all //
// pointers into the file before this point may be invalidated. //
//////////////////////////////////////////////////////////////////
// walk to end of list
while( pListGroup->dwNext ) { pListGroup = _pContainer->_UrlObjStorage->ValidateListGroupOffset( pListGroup->dwNext); if( !pListGroup ) { dwError = ERROR_INTERNET_INTERNAL_ERROR; goto Cleanup; } }
// Get ListGroupEmpty Object from the empty slot
pListGroupEmpty = _pContainer->_UrlObjStorage->ValidateListGroupOffset(dwEmptySlot); if( !pListGroupEmpty ) { dwError = ERROR_INTERNET_INTERNAL_ERROR; goto Cleanup; }
// assign the new offset
pListGroupEmpty->dwGroupOffset = dwOffset;
// append empty slot at the end of the list
// this need to be done at last to prevent some invalid
// object get on the list
pListGroup->dwNext = dwEmptySlot; }
dwError = ERROR_SUCCESS;
Cleanup: return dwError; }
DWORD GroupMgr::RemoveFromGroupList( DWORD dwHeadOffset, DWORD dwOffset, LPDWORD pdwNewHeadOffset ) { DWORD dwError = ERROR_SUCCESS; LIST_GROUP_ENTRY* pListGroup = NULL; LIST_GROUP_ENTRY* pListGroupPrev = NULL; LPBYTE lpbBase = NULL;
pListGroup = _pContainer->_UrlObjStorage->ValidateListGroupOffset(dwHeadOffset); if( !pListGroup ) { dwError = ERROR_FILE_NOT_FOUND; goto Cleanup; }
lpbBase = (LPBYTE) *_pContainer->_UrlObjStorage->GetHeapStart();
// header is the one we need, we will have to assign new header
if( pListGroup->dwGroupOffset == dwOffset ) { // new head
*pdwNewHeadOffset = pListGroup->dwNext;
// empty removed head and added to free list
pListGroup->dwGroupOffset = 0; pListGroup->dwNext= 0; AddToFreeList(pListGroup);
// done
dwError = ERROR_SUCCESS; goto Cleanup; }
if( !pListGroup->dwNext ) { dwError = ERROR_FILE_NOT_FOUND; goto Cleanup; }
pListGroupPrev = pListGroup; pListGroup = _pContainer->_UrlObjStorage->ValidateListGroupOffset(pListGroup->dwNext); if( !pListGroup) { dwError = ERROR_FILE_NOT_FOUND; goto Cleanup; }
while( pListGroup ) { INET_ASSERT(pListGroup->dwGroupOffset);
if( pListGroup->dwGroupOffset == dwOffset ) { pListGroupPrev->dwNext = pListGroup->dwNext;
// empty removed item and added it to free list
pListGroup->dwGroupOffset = 0; pListGroup->dwNext= 0; AddToFreeList(pListGroup);
dwError = ERROR_SUCCESS; break; }
if( pListGroup->dwNext ) { pListGroupPrev = pListGroup; pListGroup = _pContainer->_UrlObjStorage->ValidateListGroupOffset(pListGroup->dwNext); } else { dwError = ERROR_FILE_NOT_FOUND; break;
} }
Cleanup: return dwError; }
DWORD GroupMgr::FindEmptySlotInListPage(DWORD* pdwOffsetToSlot) {
DWORD dwError; DWORD dwOffsetRoot = 0; LPBYTE lpbBase = NULL; LIST_GROUP_ENTRY* pListGroupFreeHead = NULL; LIST_GROUP_ENTRY* pListGroupEmpty = NULL;
if( !GetHeaderData( CACHE_HEADER_DATA_ROOT_GROUPLIST_OFFSET, &dwOffsetRoot)) { dwError = ERROR_INTERNET_INTERNAL_ERROR; goto Cleanup; }
if( !dwOffsetRoot) { // new page needs to be created
dwError = CreateNewListPage(&dwOffsetRoot, TRUE);
if( dwError != ERROR_SUCCESS) goto Cleanup; }
//
// At this point, we've got the root entry
// 1. retrieved valid dwOffsetToRootEntry or
// 2. get the new dwOffsetToRootEntry via CreateNewPage() call
//
INET_ASSERT( dwOffsetRoot);
lpbBase = (LPBYTE) *_pContainer->_UrlObjStorage->GetHeapStart(); pListGroupFreeHead = (LIST_GROUP_ENTRY*) (lpbBase + dwOffsetRoot); if( !pListGroupFreeHead ) { dwError = ERROR_INTERNET_INTERNAL_ERROR; goto Cleanup; }
//////////////////////////////////////////////////////////////////
// BEGIN WARNING: The file might be grown and remapped, so all //
// pointers into the file before this point may be invalidated. //
//////////////////////////////////////////////////////////////////
// get the next free item from the list
if( !pListGroupFreeHead->dwNext ) { // no free slot left!, let's create a new page!
// remember the old offset free list head entry
DWORD_PTR dwpFreeHeadOffset = PtrDifference(pListGroupFreeHead, lpbBase);
// create a new page
DWORD dwNewList; dwError = CreateNewListPage(&dwNewList, FALSE);
if( dwError != ERROR_SUCCESS) goto Cleanup;
// restore
lpbBase = (LPBYTE) *_pContainer->_UrlObjStorage->GetHeapStart(); pListGroupFreeHead = (LIST_GROUP_ENTRY*) (lpbBase + dwpFreeHeadOffset); //
// add the newly created page contains a list of empty
// slot (already chained together), now update the head
// of free list pointing to the head of the newly created
// list
//
pListGroupFreeHead->dwNext = dwNewList; } //////////////////////////////////////////////////////////////////
// END WARNING: The file might be grown and remapped, so all //
// pointers into the file before this point may be invalidated. //
//////////////////////////////////////////////////////////////////
// get the empty slot offset
*pdwOffsetToSlot = pListGroupFreeHead->dwNext;
// update the free list to point to the next slot
pListGroupEmpty = (LIST_GROUP_ENTRY*)(lpbBase + pListGroupFreeHead->dwNext); pListGroupFreeHead->dwNext = pListGroupEmpty->dwNext; memset(pListGroupEmpty, 0, sizeof(LIST_GROUP_ENTRY) ); dwError = ERROR_SUCCESS;
Cleanup: return dwError; }
DWORD GroupMgr::CreateNewListPage(DWORD* pdwOffsetToFirstEntry, BOOL fIsFirstPage) { DWORD dwError; GROUPS_ALLOC_FILEMAP_ENTRY* pPage = NULL; DWORD cbSize = sizeof(GROUPS_ALLOC_FILEMAP_ENTRY);
pPage = (GROUPS_ALLOC_FILEMAP_ENTRY*) _pContainer->_UrlObjStorage->AllocateEntry(cbSize);
if( pPage ) { // clean up allocated page
cbSize = PAGE_SIZE_FOR_GROUPS; memset(pPage->pGroupBlock, 0, cbSize );
// calculate the group base offset
LPBYTE lpbBase = (LPBYTE) *_pContainer->_UrlObjStorage->GetHeapStart();
*pdwOffsetToFirstEntry = PtrDiff32(pPage->pGroupBlock, lpbBase);
//
// chain all items together
// (Last item will have dwNext == 0 since we have alredy memset
// the whole page )
//
LIST_GROUP_ENTRY* pList = (LIST_GROUP_ENTRY*) pPage->pGroupBlock;
for( DWORD dwi = 0; dwi < (LIST_GROUPS_PER_PAGE -1); dwi++) { pList->dwNext = PtrDiff32(pList+1, lpbBase); pList++ ; }
if( fIsFirstPage ) { //
// for first page, we would have to set the offset
// back to the CacheHeader
//
if( !SetHeaderData( CACHE_HEADER_DATA_ROOT_GROUPLIST_OFFSET, *pdwOffsetToFirstEntry)) { // free allocated page
_pContainer->_UrlObjStorage->FreeEntry(pPage); // set error and go
*pdwOffsetToFirstEntry = 0; dwError = ERROR_INTERNET_INTERNAL_ERROR; goto Cleanup;
} // IF: failed to set the offset
} // return the offset to the first entry of the new page
dwError = ERROR_SUCCESS;
} // IF: Allocate new page succeed
else { dwError = ERROR_NOT_ENOUGH_MEMORY; } // ELSE: failed to allocate new page
Cleanup: return dwError; }
BOOL GroupMgr::IsGroupOnList(DWORD dwHeadOffset, DWORD dwGrpOffset) { BOOL fRet = FALSE; LIST_GROUP_ENTRY* pListGroup = NULL;
LIST_GROUP_ENTRY *pMilestone = NULL; // used for detecting cycles
unsigned long dwNodeCount = 1;
pListGroup = _pContainer->_UrlObjStorage->ValidateListGroupOffset(dwHeadOffset); if( !pListGroup ) { goto Cleanup; }
while( pListGroup ) { //INET_ASSERT(pListGroup->dwGroupOffset);
if( pListGroup->dwGroupOffset == dwGrpOffset ) { fRet = TRUE; break; }
if( pListGroup->dwNext ) { LIST_GROUP_ENTRY* plgTemp = _pContainer->_UrlObjStorage->ValidateListGroupOffset( pListGroup->dwNext);
// Sometimes the list is corrupted and contains a cycle
// This is detected by comparing against the saved pointer
// (Revisiting an earlier milestone indicates a cycle)
if (plgTemp==pMilestone) break;
// Also check (and fix) simple self-loops
if (plgTemp==pListGroup) { pListGroup->dwNext = 0; break; }
// Advance to next node
pListGroup = plgTemp;
// Choose new milestone when node count is power of 2
dwNodeCount++;
if ((dwNodeCount & (dwNodeCount-1)) == 0) pMilestone = pListGroup; } else { break; } }
Cleanup: return fRet; }
BOOL GroupMgr::NoMoreStickyEntryOnList(DWORD dwHeadOffset) { BOOL fRet = FALSE; LIST_GROUP_ENTRY* pListGroup = NULL; GROUP_ENTRY* pGroupEntry = NULL;
pListGroup = _pContainer->_UrlObjStorage->ValidateListGroupOffset(dwHeadOffset); if( !pListGroup ) { goto Cleanup; }
while( pListGroup ) { //INET_ASSERT(pListGroup->dwGroupOffset);
// get the GroupEntry structure
if( !_pContainer->_UrlObjStorage->IsBadGroupOffset( pListGroup->dwGroupOffset) ) { pGroupEntry = (GROUP_ENTRY*) ( *_pContainer->_UrlObjStorage->GetHeapStart() + pListGroup->dwGroupOffset );
// IsSticky?
if( IsStickyGroup(pGroupEntry->gid) ) { goto Cleanup; } }
// end of list
if( !pListGroup->dwNext ) { break; }
// next item on list
pListGroup = _pContainer->_UrlObjStorage->ValidateListGroupOffset( pListGroup->dwNext); }
//
// reach here means we are at end of the list and can not find
// any sticky group, return TRUE
//
fRet = TRUE;
Cleanup: return fRet;
}
void GroupMgr::AdjustUsageOnList(DWORD dwHeadOffset, LONGLONG llDelta) { LIST_GROUP_ENTRY* pListGroup = NULL; GROUP_ENTRY* pGroupEntry = NULL;
pListGroup = _pContainer->_UrlObjStorage->ValidateListGroupOffset(dwHeadOffset); if( !pListGroup ) { goto Cleanup; }
while( pListGroup ) { // INET_ASSERT(pListGroup->dwGroupOffset);
// get the GroupEntry structure
if( !_pContainer->_UrlObjStorage->IsBadGroupOffset( pListGroup->dwGroupOffset) ) { pGroupEntry = (GROUP_ENTRY*) ( *_pContainer->_UrlObjStorage->GetHeapStart() + pListGroup->dwGroupOffset );
// AdjustUsage
_pContainer->AdjustGroupUsage(pGroupEntry, llDelta); }
// end of list
if( !pListGroup->dwNext ) { goto Cleanup; }
// next item on list
pListGroup = _pContainer->_UrlObjStorage->ValidateListGroupOffset( pListGroup->dwNext); }
Cleanup: return;
}
void GroupMgr::AddToFreeList(LIST_GROUP_ENTRY* pFreeListGroup) { DWORD dwOffsetRoot = 0; LIST_GROUP_ENTRY* pFreeListHead = NULL; if( GetHeaderData( CACHE_HEADER_DATA_ROOT_GROUPLIST_OFFSET, &dwOffsetRoot)) {
pFreeListHead = _pContainer->_UrlObjStorage->ValidateListGroupOffset(dwOffsetRoot); if( pFreeListHead && pFreeListGroup ) { pFreeListGroup->dwNext = pFreeListHead->dwNext;
pFreeListHead->dwNext = PtrDiff32(pFreeListGroup, *_pContainer->_UrlObjStorage->GetHeapStart()); } } return; }
|