//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1992. // // File: dl.cxx // // Contents: Delta list code for streams // // Classes: Defined in dl.hxx // // History: 28-Jul-92 PhilipLa Created. // //-------------------------------------------------------------------------- #include "msfhead.cxx" #pragma hdrstop #include #include #include #ifndef _MAC inline #endif void *SDeltaBlock::operator new(size_t size, IMalloc * const pMalloc) { return pMalloc->Alloc(size); } //+------------------------------------------------------------------------- // // Method: SDeltaBlock::SDeltaBlock, public // // Synopsis: SDeltaBlock constructor // // History: 10-Jul-92 PhilipLa Created. // //-------------------------------------------------------------------------- #ifndef _MAC inline #endif SDeltaBlock::SDeltaBlock() { for (USHORT i = 0; i < CSECTPERBLOCK; i++) { _sect[i] = ENDOFCHAIN; } for (i = 0; i < CSECTPERBLOCK / CBITPERUSHORT; i++) { _fOwn[i] = 0; } } //+------------------------------------------------------------------------- // // Method: CDeltaList::CDeltaList, public // // Synopsis: CDeltaList constructor // // History: 21-Jan-92 PhilipLa Created. // // Notes: // //-------------------------------------------------------------------------- CDeltaList::CDeltaList(CMStream *pms, CMStream *pmsScratch) { _pms = P_TO_BP(CBasedMStreamPtr, pms); _pmsScratch = P_TO_BP(CBasedMStreamPtr, pmsScratch); _apdb = NULL; _sectStart = ENDOFCHAIN; _ulSize = 0; _ptsParent = NULL; } inline CBasedDeltaBlockPtr * CDeltaList::GetNewDeltaArray(ULONG ulSize) { msfAssert(ulSize > 0); if (ulSize > (_HEAP_MAXREQ / sizeof(SDeltaBlock *))) { return NULL; } return (CBasedDeltaBlockPtr *) _pmsScratch->GetMalloc()-> Alloc(sizeof(SDeltaBlock *) * ulSize); } //+------------------------------------------------------------------------- // // Method: CDeltaList::Init, public // // Synopsis: Init function for CDeltaList // // Arguments: [ulSize] -- Size of delta list to be initialized // [ptsParent] -- Pointer to transacted stream that contains // this delta list. // // Returns: S_OK if call completed successfully. // // Algorithm: *Finish This* // // History: 21-Jan-92 PhilipLa Created. // //-------------------------------------------------------------------------- #ifdef LARGE_STREAMS SCODE CDeltaList::Init(ULONGLONG ulSize, CTransactedStream *ptsParent) #else SCODE CDeltaList::Init(ULONG ulSize, CTransactedStream *ptsParent) #endif { SCODE sc = S_OK; ULONG ulNewSize; CBasedDeltaBlockPtr *apdbTemp = NULL; msfAssert(IsEmpty() && aMsg("Init called on non-empty delta list.")); ULONG cbSector = GetDataSectorSize(); ULONG csect = (ULONG)((ulSize + cbSector - 1) / cbSector); ulNewSize = (csect + CSECTPERBLOCK - 1) / CSECTPERBLOCK; _ulSize = ulNewSize; _ptsParent = P_TO_BP(CBasedTransactedStreamPtr, ptsParent); CDeltaList *pdlParent = NULL; if (_ptsParent->GetBase() != NULL) { pdlParent = _ptsParent->GetBase()->GetDeltaList(); } msfAssert(_ulSize > 0); msfAssert(IsEmpty()); // if the parent is InStream, we stay in low-memory mode if ((pdlParent == NULL) || (pdlParent->IsInMemory())) { //Try to copy it down. If it doesn't work, put it in a stream //instead. msfMem(apdbTemp = GetNewDeltaArray(_ulSize)); MAXINDEXTYPE i; for (i = 0; i < _ulSize; i++) { apdbTemp[i] = NULL; } if (pdlParent != NULL) { for (i = 0; i < _ulSize; i++) { if ((i < pdlParent->_ulSize) && (pdlParent->_apdb[i] != NULL)) { SDeltaBlock *pdbTemp; msfMemTo(Err_Alloc, pdbTemp = new(_pmsScratch->GetMalloc()) SDeltaBlock); apdbTemp[i] = P_TO_BP(CBasedDeltaBlockPtr, pdbTemp); for (USHORT j = 0; j < CSECTPERBLOCK; j++) { pdbTemp->_sect[j] = pdlParent->_apdb[i]->_sect[j]; } } } } _apdb = P_TO_BP(CBasedDeltaBlockPtrPtr, apdbTemp); return S_OK; Err_Alloc: for (i = 0; i < _ulSize; i++) { _pmsScratch->GetMalloc()->Free(BP_TO_P(SDeltaBlock *, apdbTemp[i])); apdbTemp[i] = NULL; } } Err: _apdb = NULL; //We'll end up here if we get an error allocating memory for // the InMemory case above or if the parent is InStream. We // must allocate a new stream and copy down the parent. if (pdlParent == NULL) { for (ULONG i = 0; i < _ulSize; i++) { msfChkTo(Err_Init, InitStreamBlock(i)); } } else { //Copy the parent into a stream representation. for (ULONG i = 0; i < min(_ulSize, pdlParent->_ulSize) * CSECTPERBLOCK; i++) { SECT sectOld; msfChkTo(Err_Init, pdlParent->GetMap(i, DL_READ, §Old)); msfChkTo(Err_Init, WriteMap(&_sectStart, i, sectOld)); } for (i = pdlParent->_ulSize; i < _ulSize; i++) { msfChkTo(Err_Init, InitStreamBlock(i)); } } Err_Init: return sc; } //+------------------------------------------------------------------------- // // Method: CDeltaList::InitResize, public // // Synopsis: Resize initializer for deltalists // // Arguments: [ulSize] -- Size of new deltalist // [pdlOld] -- Pointer to deltalist to be resized // // Returns: S_OK if call completed OK. // // Algorithm: *Finish This* // // History: 21-Jan-92 PhilipLa Created. // //-------------------------------------------------------------------------- #ifdef LARGE_STREAMS SCODE CDeltaList::InitResize(ULONGLONG ulSize) #else SCODE CDeltaList::InitResize(ULONG ulSize) #endif { msfDebugOut((DEB_ITRACE,"In CDeltaList copy constructor\n")); SCODE sc = S_OK; CBasedDeltaBlockPtr *temp = NULL; CBasedDeltaBlockPtr *apdbTemp = NULL; ULONG cbSector = GetDataSectorSize(); ULONG csect = (ULONG)((ulSize + cbSector - 1) / cbSector); ULONG ulNewSize = (csect + CSECTPERBLOCK - 1) / CSECTPERBLOCK; msfAssert(ulNewSize > 0); if (ulNewSize == _ulSize) { return S_OK; } if (IsInStream()) { //We have already copied the delta list contents out to the // stream, and will not attempt to read them back in. // //All we need to do is adjust the size and return. if (ulNewSize > _ulSize) { for (ULONG i = _ulSize; i < ulNewSize; i++) { msfChk(InitStreamBlock(i)); } } _ulSize = ulNewSize; return S_OK; } if (ulNewSize > (_HEAP_MAXREQ / sizeof(SDeltaBlock *))) { //This is not an error. Write the current delta information // to the stream and use that. msfChk(DumpList()); if (ulNewSize > _ulSize) { for (ULONG i = _ulSize; i < ulNewSize; i++) { msfChk(InitStreamBlock(i)); } } _ulSize = ulNewSize; return S_OK; } msfMemTo(ErrMem, temp = GetNewDeltaArray(ulNewSize)); //apdbTemp is an unbased version of _apdb, for efficiency. apdbTemp = BP_TO_P(CBasedDeltaBlockPtr *, _apdb); ULONG i; if (apdbTemp != NULL) { for (i = 0; i < min(_ulSize, ulNewSize); i++) { temp[i] = apdbTemp[i]; apdbTemp[i] = NULL; } } for (i = _ulSize; i < ulNewSize; i++) { temp[i] = NULL; } for (i = ulNewSize; i < _ulSize; i++) { ReleaseBlock(i); } _ulSize = ulNewSize; _pmsScratch->GetMalloc()->Free(apdbTemp); _apdb = P_TO_BP(CBasedDeltaBlockPtrPtr, temp); return S_OK; ErrMem: //The only error that can get us here is an error allocating temp. //If this happens, dump the current vector to a stream and use // the stream for all future delta list operations. msfChk(DumpList()); if (ulNewSize > _ulSize) { for (i = _ulSize; i < ulNewSize; i++) { msfChk(InitStreamBlock(i)); } } _ulSize = ulNewSize; return S_OK; Err: //We only get here if we error out on the DumpList() or //InitStreamBlock calls (i.e. Disk Error) return sc; } //+--------------------------------------------------------------------------- // // Member: CDeltaList::InitStreamBlock, private // // Synopsis: Initialize a new block in a stream // // Arguments: [ulBlock] -- Block to initialize // // Returns: Appropriate status code // // History: 20-Nov-92 PhilipLa Created // // Notes: // //---------------------------------------------------------------------------- SCODE CDeltaList::InitStreamBlock(ULONG ulBlock) { SCODE sc = S_OK; ULONG cSectOld = ulBlock * CSECTPERBLOCK; ULONG cSectNew = (ulBlock + 1) * CSECTPERBLOCK; //NOTE: This can potentially be optimized to avoid the loop. for (ULONG i = cSectOld; i < cSectNew; i++) { msfChk(WriteMap(&_sectStart, i, ENDOFCHAIN)); } Err: return sc; } //+------------------------------------------------------------------------- // // Method: CDeltaList::ReleaseBlock, private // // Synopsis: Release an SDeltaBlock, freeing its storage in the // scratch MS. // // Arguments: [oBlock] -- Offset of block to release. // // Returns: void. // // History: 10-Jul-92 PhilipLa Created. // //-------------------------------------------------------------------------- void CDeltaList::ReleaseBlock(ULONG oBlock) { CFat *pfat = GetDataFat(); msfAssert(IsInMemory()); SDeltaBlock *temp = BP_TO_P(SDeltaBlock *, _apdb[(MAXINDEXTYPE)oBlock]); if (temp != NULL) { for (USHORT i = 0; i < CSECTPERBLOCK; i++) { if ((temp->_sect[i] != ENDOFCHAIN) && temp->IsOwned(i)) { SECT sectCurrent = FREESECT; pfat->GetNext(temp->_sect[i], §Current); if (sectCurrent == STREAMSECT) pfat->SetNext(temp->_sect[i], FREESECT); } } _pmsScratch->GetMalloc()->Free(temp); _apdb[(MAXINDEXTYPE)oBlock] = NULL; } } //+------------------------------------------------------------------------- // // Method: CDeltaList::~CDeltaList, public // // Synopsis: CDeltaList destructor // // History: 21-Jan-92 PhilipLa Created. // //-------------------------------------------------------------------------- CDeltaList::~CDeltaList() { Empty(); } //+------------------------------------------------------------------------- // // Method: CDeltaList::GetMap, public // // Synopsis: Get mapping information for a sector // // Arguments: [sectOld] -- Sector to get mapping information for // [dwFlags] -- DL_GET or DL_CREATE // [psectRet] -- Location for return value // [pfIsOwner] -- Returns TRUE if the returned sector // is owned by this delta list, FALSE if it // if owned by an ancestor. // // Returns: S_OK if call completed OK. // // Algorithm: If DL_READ is specified, return the current existing // mapping for the sector. It is not required that // the delta list own the sector. Return ENDOFCHAIN // if no mapping exists. // If DL_GET is specified, return the current existing // mapping for the sector if it is owned by this delta // list. If none exists, return ENDOFCHAIN. // If DL_CREATE, check the existing mapping. If none // exists, or one exists but is not owned, get a free // sector from the fat and set the mapping. Return // the new mapping (or the existing one if it had // previously been mapped). // // History: 21-Jan-92 PhilipLa Created. // 10-Jul-92 PhilipLa Changed for copy reductions. // //-------------------------------------------------------------------------- SCODE CDeltaList::GetMap(SECT sectOld, const DWORD dwFlags, SECT *psectRet) { msfDebugOut((DEB_ITRACE,"In CDeltaList::GetMap()\n")); SCODE sc = S_OK; msfAssert(!IsEmpty()); msfAssert((dwFlags == DL_GET) || (dwFlags == DL_CREATE) || (dwFlags == DL_READ)); MAXINDEXTYPE odb = (MAXINDEXTYPE)(sectOld / CSECTPERBLOCK); USHORT os = (USHORT)(sectOld % CSECTPERBLOCK); msfAssert(odb < _ulSize); if (IsInStream()) { BOOL fOwn = TRUE; msfChk(ReadMap(&_sectStart, sectOld, psectRet)); if (dwFlags == DL_READ) { return S_OK; } CDeltaList *pdlParent = NULL; if (_ptsParent->GetBase() != NULL) pdlParent = _ptsParent->GetBase()->GetDeltaList(); if (pdlParent != NULL) { msfChk(pdlParent->IsOwned(sectOld, *psectRet, &fOwn)); } if (fOwn == FALSE) *psectRet = ENDOFCHAIN; if ((dwFlags == DL_CREATE) && (*psectRet == ENDOFCHAIN)) { msfChk(GetDataFat()->GetFree(1, psectRet, GF_WRITE)); msfChk(GetDataFat()->SetNext(*psectRet, STREAMSECT)); if(!IsNoScratch()) msfChk(_pmsScratch->SetSize()); else msfChk(_pms->SetSize()); msfChk(WriteMap(&_sectStart, sectOld, *psectRet)); } return S_OK; } msfAssert(odb < _ulSize); // If _apdb[odb] == NULL, there is no existing mapping so we // don't need to check ownership. if (_apdb[odb] == NULL) { if (dwFlags & DL_CREATE) { SDeltaBlock * pdbTemp = new(_pmsScratch->GetMalloc()) SDeltaBlock; _apdb[odb] = P_TO_BP(CBasedDeltaBlockPtr, pdbTemp); if (_apdb[odb] == NULL) { msfChk(DumpList()); msfAssert(IsInStream()); return GetMap(sectOld, dwFlags, psectRet); } } else { *psectRet = ENDOFCHAIN; return S_OK; } } SECT sectTemp; sectTemp = _apdb[odb]->_sect[os]; if (dwFlags != DL_READ) { BOOL fOwn = _apdb[odb]->IsOwned(os); if (fOwn == FALSE) sectTemp = ENDOFCHAIN; if ((dwFlags == DL_CREATE) && (sectTemp == ENDOFCHAIN)) { // // Don't grow the file (w/ SetSize) here. As an optimzation // it is the responsibility of the caller to grow the file after // possibly multiple calls to GetMap(DL_CREATE). // msfChk(GetDataFat()->GetFree(1, §Temp, GF_WRITE)); msfChk(GetDataFat()->SetNext(sectTemp, STREAMSECT)); _apdb[odb]->_sect[os] = sectTemp; _apdb[odb]->MakeOwn(os); } } *psectRet = sectTemp; msfDebugOut((DEB_ITRACE,"Out CDeltaList::GetMap()\n")); Err: return sc; } //+------------------------------------------------------------------------- // // Method: CDeltaList::ReleaseInvalidSects, public // // Synopsis: Release sectors allocated in the FAT that are not in the // MStream. // // Arguments: [sectMaxValid] -- Release all SECTS greater than this one. // // Returns: S_OK if call completed OK. // // Algorithm: // // History: 26-Mar-97 BChapman Created. // //-------------------------------------------------------------------------- SCODE CDeltaList::ReleaseInvalidSects(SECT sectMaxValid) { msfDebugOut((DEB_ITRACE,"In CDeltaList::ReleaseInvalidSects(%x)\n", sectMaxValid)); msfAssert(!IsEmpty()); CBasedDeltaBlockPtr *apdbTemp; // Real Ptr to array of Based Pointers SDeltaBlock *pdbTemp; CFat *pfat = GetDataFat(); if (IsInStream()) { // We don't need to do this if we are InStream. return S_OK; } apdbTemp = _apdb; // Convert the array BasedPtr to a Ptr. // // Walk the entire Delta List looking for SECTS in the FAT that are // greater than sectMaxValid, and free them. // If all the entries in any block are freed, then free the block. // for (MAXINDEXTYPE i = 0; i < _ulSize; i++) { pdbTemp = _apdb[i]; // Convert BasedPtr to Ptr if (pdbTemp != NULL) { BOOL fFreeAll = TRUE; for (USHORT k=0; k < CSECTPERBLOCK; k++) { SECT sectType=FREESECT; SECT sectEntryK = pdbTemp->_sect[k]; if(sectEntryK != ENDOFCHAIN) { if(pdbTemp->IsOwned(k) && (sectEntryK > sectMaxValid)) { // // This routins is already in the error path. So we // don't check for errors. Just keep pluggin away. // BTW. There shouldn't be any errors because we just // allocated all this stuff and we are only tring to // give it back. // pfat->GetNext(sectEntryK, §Type); if (sectType == STREAMSECT) { pfat->SetNext(sectEntryK, FREESECT); pdbTemp->DisOwn(k); pdbTemp->_sect[k] = ENDOFCHAIN; } } else { // don't free this DeltaBlock if any non-ENDOFCHAIN // entries are not owned or are valid (<= MaxValid) fFreeAll = FALSE; } } } if(fFreeAll) { _pmsScratch->GetMalloc()->Free(pdbTemp); _apdb[i] = NULL; } } } msfDebugOut((DEB_ITRACE,"Out CDeltaList::ReleaseInvalidSects()\n")); return S_OK; } //+--------------------------------------------------------------------------- // // Member: CDeltaList::BeginCommit, public // // Synopsis: Begin the commit of a delta list // // Arguments: [ptsParent] -- Pointer to containing Tstream. // // Returns: Appropriate status code // // History: 19-Nov-92 PhilipLa Created // //---------------------------------------------------------------------------- void CDeltaList::BeginCommit(CTransactedStream *ptsParent) { _ptsParent = P_TO_BP(CBasedTransactedStreamPtr, ptsParent); } //+------------------------------------------------------------------------- // // Method: CDeltaList::EndCommit, public // // Synopsis: Take the new delta list passed up and release the old. // Free any sectors used and owned in the old list but not // in the new. // // Arguments: [pdlNew] -- Pointer to new delta list to take // // Returns: void. // // History: 10-Jul-92 PhilipLa Created. // //-------------------------------------------------------------------------- void CDeltaList::EndCommit(CDeltaList *pdlNew, DFLAGS df) { msfAssert(pdlNew != NULL); if (pdlNew->IsEmpty()) return; ULONG ulMaxSize = min(_ulSize, pdlNew->_ulSize); if (P_COMMIT(df)) { #if DBG == 1 msfDebugOut((DEB_ITRACE, "Beginning commit process:\n")); PrintList(); msfDebugOut((DEB_ITRACE, "New list is:\n")); pdlNew->PrintList(); #endif ULONG iMax = ulMaxSize * CSECTPERBLOCK; for (ULONG i = 0; i < iMax; i++) { SECT sectOld = ENDOFCHAIN, sectNew = ENDOFCHAIN; GetMap(i, DL_GET, §Old); pdlNew->GetMap(i, DL_GET, §New); if ((sectOld != sectNew) && (sectOld != ENDOFCHAIN) && (sectNew != ENDOFCHAIN)) { CFat *pfat = GetDataFat(); SECT sectChk; pfat->GetNext(sectOld, §Chk); if (sectChk == STREAMSECT) pfat->SetNext(sectOld, FREESECT); } } //At this point, all the sectors in the current delta list // that are not used in the new delta list have been freed. // We still need to clean up the actual representation of // the delta list, and merge the ownership bitvectors if // we are InMemory. if (IsInMemory()) { for (i = pdlNew->_ulSize; i < _ulSize; i++) { ReleaseBlock(i); } CBasedDeltaBlockPtr * apdbTemp; apdbTemp = BP_TO_P(CBasedDeltaBlockPtr *, _apdb); for (MAXINDEXTYPE i = 0; i < ulMaxSize; i++) { if ((apdbTemp[i] != NULL) && (pdlNew->IsInMemory())) { msfAssert(pdlNew->_apdb[i] != NULL); for (USHORT j = 0; j < CSECTPERBLOCK / CBITPERUSHORT; j++) { pdlNew->_apdb[i]->_fOwn[j] |= apdbTemp[i]->_fOwn[j]; } } _pmsScratch->GetMalloc()->Free(BP_TO_P(SDeltaBlock *, apdbTemp[i])); } _pmsScratch->GetMalloc()->Free(apdbTemp); } else if (IsInStream()) { for (i = pdlNew->_ulSize * CSECTPERBLOCK; i < _ulSize * CSECTPERBLOCK; i++) { SECT sectOld = ENDOFCHAIN; GetMap(i, DL_GET, §Old); if (sectOld != ENDOFCHAIN) { CFat *pfat = GetDataFat(); #if DBG == 1 SECT sectChk; pfat->GetNext(sectOld, §Chk); msfAssert((sectChk == STREAMSECT) && aMsg("Freeing non-dirty stream sector")); #endif pfat->SetNext(sectOld, FREESECT); } } GetControlFat()->SetChainLength(_sectStart, 0); } _apdb = pdlNew->_apdb; _ulSize = pdlNew->_ulSize; _sectStart = pdlNew->_sectStart; pdlNew->_apdb = NULL; pdlNew->_ulSize = 0; pdlNew->_sectStart = ENDOFCHAIN; pdlNew->_ptsParent = NULL; #if DBG == 1 msfDebugOut((DEB_ITRACE, "Completed commit process:\n")); PrintList(); #endif } return; } //+--------------------------------------------------------------------------- // // Member: CDeltaList::Empty, public // // Synopsis: Empty the delta list // // Arguments: None. // // History: 18-Nov-92 PhilipLa Created // //---------------------------------------------------------------------------- void CDeltaList::Empty(void) { if (IsInMemory()) { msfAssert(_sectStart == ENDOFCHAIN); CBasedDeltaBlockPtr * apdbTemp; apdbTemp = BP_TO_P(CBasedDeltaBlockPtr *, _apdb); for (ULONG i = 0; i < _ulSize; i++) { if (apdbTemp[i] != NULL) { ReleaseBlock(i); } } _pmsScratch->GetMalloc()->Free(apdbTemp); _apdb = NULL; } else if (IsInStream()) { msfAssert(_apdb == NULL); if (_sectStart != ENDOFCHAIN) { FreeStream(_sectStart, _ulSize); } _sectStart = ENDOFCHAIN; } _ptsParent = NULL; _ulSize = 0; } //+--------------------------------------------------------------------------- // // Member: CDeltaList::DumpList, public // // Synopsis: Dump a delta list out to a stream, then release its // in memory representation. // // Arguments: None. // // Returns: Appropriate status code // // History: 20-Nov-92 PhilipLa Created // //---------------------------------------------------------------------------- SCODE CDeltaList::DumpList(void) { SCODE sc = S_OK; ULONG cSect = _ulSize * CSECTPERBLOCK; msfAssert(IsInMemory()); for (ULONG i = 0; i < cSect; i++) { SECT sectNew; msfChk(GetMap(i, DL_GET, §New)); msfChk(WriteMap(&_sectStart, i, sectNew)); } CBasedDeltaBlockPtr * apdbTemp; apdbTemp = BP_TO_P(CBasedDeltaBlockPtr *, _apdb); if (apdbTemp != NULL) { for (i = 0; i < _ulSize; i++) { SDeltaBlock *temp = BP_TO_P(SDeltaBlock *, apdbTemp[i]); if (temp != NULL) { _pmsScratch->GetMalloc()->Free(temp); } } _pmsScratch->GetMalloc()->Free(apdbTemp); _apdb = NULL; } msfAssert(IsInStream()); Err: return sc; } //+--------------------------------------------------------------------------- // // Member: CDeltaList::FindOffset, private // // Synopsis: Compute the correct offset from which to read a mapping // // Arguments: [psectStart] -- Pointer to start sector // [sect] -- Sector to find mapping for // [pulRet] -- Pointer to return location // [fWrite] -- TRUE if the sector will be written to // // Returns: Appropriate status code // // History: 20-Nov-92 PhilipLa Created // //---------------------------------------------------------------------------- SCODE CDeltaList::FindOffset( SECT *psectStart, SECT sect, ULARGE_INTEGER *pulRet, BOOL fWrite) { SCODE sc; ULONG ulOffset = sect * sizeof(SECT); ULONG cbSector = GetControlSectorSize(); msfAssert(cbSector == SCRATCHSECTORSIZE); SECT sectChain = ulOffset / cbSector; SECT sectReal; CFat *pfat = GetControlFat(); if (fWrite) { if (*psectStart == ENDOFCHAIN) { msfChk(pfat->Allocate(1, psectStart)); } msfChk(pfat->GetESect(*psectStart, sectChain, §Real)); } else { msfChk(pfat->GetSect(*psectStart, sectChain, §Real)); } msfAssert(sectReal != ENDOFCHAIN); ULARGE_INTEGER ul; #ifdef LARGE_DOCFILE ul.QuadPart = ConvertSectOffset(sectReal, (OFFSET)(ulOffset % cbSector), _pmsScratch->GetSectorShift()); #else ULISet32(ul, ConvertSectOffset(sectReal, (OFFSET)(ulOffset % cbSector), _pmsScratch->GetSectorShift())); #endif *pulRet = ul; Err: return sc; } //+--------------------------------------------------------------------------- // // Member: CDeltaList::ReadMap, private // // Synopsis: Read a mapping from a stream representation. // // Arguments: [sect] -- Sector to read mapping for // [psectRet] -- Location to return mapping in. // // Returns: Appropriate status code // // History: 20-Nov-92 PhilipLa Created // //---------------------------------------------------------------------------- SCODE CDeltaList::ReadMap(SECT *psectStart, SECT sect, SECT *psectRet) { SCODE sc; if (_sectStart == ENDOFCHAIN) { //We haven't written anything yet, so the sector must be // unmapped. *psectRet = ENDOFCHAIN; return S_OK; } ULARGE_INTEGER ul; ULONG ulRetval; msfChk(FindOffset(psectStart, sect, &ul, FALSE)); msfHChk(GetControlILB()->ReadAt(ul, psectRet, sizeof(SECT), &ulRetval)); if (ulRetval != sizeof(SECT)) { //The ILB isn't long enough to contain that mapping, *psectRet = ENDOFCHAIN; } Err: return sc; } //+--------------------------------------------------------------------------- // // Member: CDeltaList::WriteMap, private // // Synopsis: Write a mapping to a stream representation // // Arguments: [sect] -- Sect to write mapping for // [sectMap] -- Mapping of sect // // Returns: Appropriate status code // // History: 20-Nov-92 PhilipLa Created // //---------------------------------------------------------------------------- SCODE CDeltaList::WriteMap(SECT *psectStart, SECT sect, SECT sectMap) { SCODE sc; ULARGE_INTEGER ul; ULONG ulRetval; SECT sectOld = *psectStart; msfAssert(_pmsScratch->IsScratch()); msfChk(FindOffset(psectStart, sect, &ul, TRUE)); msfHChk(GetControlILB()->WriteAt(ul, §Map, sizeof(SECT), &ulRetval)); if (ulRetval != sizeof(SECT)) { msfErr(Err, STG_E_WRITEFAULT); } return S_OK; Err: //If we failed, we may have allocated sectors for storage that // cannot be written to - we should ignore these sectors. This // can leave some wasted space in the fat, but we don't really // care since this is the scratch. *psectStart = sectOld; return sc; } //+--------------------------------------------------------------------------- // // Member: CDeltaList::FreeStream, private // // Synopsis: Free the scratch sectors associated with a stream // representation of a delta list. // // Arguments: [sectStart] -- Start sector of representation to // free. // // Returns: void. // // History: 23-Nov-92 PhilipLa Created // //---------------------------------------------------------------------------- void CDeltaList::FreeStream(SECT sectStart, ULONG ulSize) { ULONG cSect = ulSize * CSECTPERBLOCK; SECT sectOld = ENDOFCHAIN; BOOL fOwn = TRUE; CDeltaList *pdlParent = NULL; if (_ptsParent->GetBase() != NULL) pdlParent = _ptsParent->GetBase()->GetDeltaList(); for (ULONG i = 0; i < cSect; i++) { ReadMap(§Start, i, §Old); if (pdlParent != NULL) { pdlParent->IsOwned(i, sectOld, &fOwn); } if ((sectOld != ENDOFCHAIN) && fOwn) { CFat *pfat = GetDataFat(); SECT sectChk = FREESECT; pfat->GetNext(sectOld, §Chk); if (sectChk == STREAMSECT) pfat->SetNext(sectOld, FREESECT); } } GetControlFat()->SetChainLength(sectStart, 0); return; } //+--------------------------------------------------------------------------- // // Member: CDeltaList::IsOwned, public // // Synopsis: Return TRUE if the caller owns the sector given, // FALSE otherwise. // // Arguments: [sect] -- Sector for mapping given // [sectMap] -- Sector mapping // [fOwn] -- Return value // // Returns: Appropriate status code // // History: 30-Jul-93 PhilipLa Created // //---------------------------------------------------------------------------- SCODE CDeltaList::IsOwned(SECT sect, SECT sectMap, BOOL *fOwn) { SCODE sc = S_OK; //To determine ownership of a sector: // 1) If the sector mapping does not exist at the current level, // then the caller must own it. // 2) If the sector mapping does exist at the current level, then // the caller cannot own it. SECT sectOld; if (sect < _ulSize * CSECTPERBLOCK) { if (IsInMemory()) { MAXINDEXTYPE odb = (MAXINDEXTYPE)(sect / CSECTPERBLOCK); USHORT os = (USHORT)(sect % CSECTPERBLOCK); sectOld = _apdb[odb]->_sect[os]; } else { msfChk(GetMap(sect, DL_READ, §Old)); } *fOwn = (sectOld != sectMap); } else { *fOwn = TRUE; } Err: return sc; } #if DBG == 1 void CDeltaList::PrintList(void) { if (!IsEmpty()) { for (ULONG i = 0; i < _ulSize * CSECTPERBLOCK; i++) { SECT sect; GetMap(i, DL_READ, §); msfDebugOut((DEB_NOCOMPNAME|DEB_ITRACE, "%lx ",sect)); } msfDebugOut((DEB_NOCOMPNAME|DEB_ITRACE,"\n")); } else { msfDebugOut((DEB_NOCOMPNAME|DEB_ITRACE,"List is empty\n")); } } #endif