diff -r 88ee4cf65e19 -r 1aa8c82cb4cb remotestoragefw/remotefileengine/src/rsfwpermanentstore.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remotestoragefw/remotefileengine/src/rsfwpermanentstore.cpp Wed Sep 01 12:15:08 2010 +0100 @@ -0,0 +1,885 @@ +/* +* Copyright (c) 2004-2006 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Provides persistent storage for memory blocks +* +*/ + + +// This is a simple block based permanent storage, in which transient +// indices are computed on the fly when all data is sequentially read +// from the storage. +// +// The data is put into "slots" that consist of one or more "blocks". +// Subsequent updates to the data slots only use the current slot +// if the required slot size (block count) has not changed. +// +// The storage contains a header that may contain any data. +// In addition, Each slot contains a header (of type TInt) that +// describes the size of the data in the slot. +// +// The file can be compressed for space efficiency. +// +// The assumption is that the store is first opened for reading for loading +// the data, and then it is only opened for writing until the file is closed. +// +// (We don't use CRsfwPermanentStore because besides data, we should +// also maintain the indices in a stream of its own) + +// INCLUDE FILES +#include +#include + +#include "rsfwpermanentstore.h" +#include "mdebug.h" + + +// CONSTANTS +const TUint KHeaderStart = 0xbabefade; +const TInt KSlotHeaderSize = 4; // sizeof(TInt) +const TInt KDefaultBlockSize = 128; // default block size in bytes +// max value for integer read from the stream, subsequently used to create descriptor +const TInt KMaxDescriptorSize = 16384; + + +// ============================ MEMBER FUNCTIONS ============================== + +// ---------------------------------------------------------------------------- +// TFileHeader::ExternalizeL +// ---------------------------------------------------------------------------- +// +void TFileHeader::ExternalizeL(RWriteStream& aStream) const + { + aStream.WriteInt32L(iHeaderStart); + aStream.WriteInt32L(iBlockSize); + aStream.WriteInt32L(iHeaderSize); + aStream << *iHeader; + } + +// ---------------------------------------------------------------------------- +// TFileHeader::InternalizeL +// ---------------------------------------------------------------------------- +// +void TFileHeader::InternalizeL(RReadStream& aStream) + { + iHeaderStart = aStream.ReadInt32L(); + iBlockSize = aStream.ReadInt32L(); + if (iBlockSize < 0 || iBlockSize > KMaxDescriptorSize) + { + User::Leave(KErrCorrupt); + } + iHeaderSize = aStream.ReadInt32L(); + if (iHeaderSize < 0 || iHeaderSize > KMaxDescriptorSize) + { + User::Leave(KErrCorrupt); + } + iHeader = HBufC8::NewL(aStream, iHeaderSize); + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::NewL +// ---------------------------------------------------------------------------- +// +CRsfwPermanentStore* CRsfwPermanentStore::NewL(const TDesC& aPath, + TInt aHeaderSize, + TInt aBlockSize) + { + CRsfwPermanentStore* self = new (ELeave) CRsfwPermanentStore(); + CleanupStack::PushL(self); + self->ConstructL(aPath, aHeaderSize, aBlockSize); + CleanupStack::Pop(self); + return self; + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::~CRsfwPermanentStore +// ---------------------------------------------------------------------------- +// +CRsfwPermanentStore::~CRsfwPermanentStore() + { + ClearFreeBlockLists(); + iSlots.Close(); + iFileReadStream.Close(); + iFileWriteStream.Close(); + iFile.Close(); + iFs.Close(); + delete iFileHeader.iHeader; + delete iZeroBlock; + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::ConstructL +// ---------------------------------------------------------------------------- +// +void CRsfwPermanentStore::ConstructL(const TDesC& aPath, + TInt aHeaderSize, + TInt aBlockSize) + { + DEBUGSTRING(("CRsfwPermanentStore::ConstructL()")); + User::LeaveIfError(iFs.Connect()); + iPath.Copy(aPath); + + iHeaderSize = aHeaderSize; + // Offset to the block data + iFileHeaderSize = iHeaderSize + sizeof(TFileHeader); + TRAPD(err, LoadHeaderL()); + if (err == KErrNone) + { + // Read parameters from the existing file, if any + iHeaderSize = iFileHeader.iHeaderSize; + iBlockSize = iFileHeader.iBlockSize; + } + else + { + // There was no existing file + DEBUGSTRING(("LoadHeaderL returns %d", err)); + if (aBlockSize) + { + iBlockSize = aBlockSize; + } + else + { + iBlockSize = KDefaultBlockSize; + } + iFileHeader.iHeaderStart = KHeaderStart; + iFileHeader.iHeaderSize = iHeaderSize; + iFileHeader.iBlockSize = iBlockSize; + } + // Compute the offset to data blocks + // (this is 4 bytes too many but that is OK ...) + iFileHeaderSize = iHeaderSize + sizeof(TFileHeader); + // Make a block of zeroes + iZeroBlock = HBufC8::NewL(iBlockSize); + iZeroBlock->Des().FillZ(); + DEBUGSTRING(("ConstructL() done, blocksize=%d", iBlockSize)); + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::ResetL +// ---------------------------------------------------------------------------- +// +void CRsfwPermanentStore::ResetL(TBool aWriting) + { + // This function is called by the client + // before starting to read or write data slots + if (aWriting) + { + SetFileStateL(EFileStateWriting); + // Set write pointer to the end of the file + MStreamBuf* streamBuf = iFileWriteStream.Sink(); + TInt size = streamBuf->SizeL(); + iWriteBlockNumber = (size - iFileHeaderSize) / iBlockSize; + if ((iWriteBlockNumber * iBlockSize) != (size - iFileHeaderSize)) + { + DEBUGSTRING(("ResetL(): file size incorrect (%d)", + size)); + } + } + else + { + // reading + SetFileStateL(EFileStateReading); + // Skip file header + MStreamBuf* streamBuf = iFileReadStream.Source(); + streamBuf->SeekL(MStreamBuf::ERead, + EStreamBeginning, + iFileHeaderSize); + iReadBlockNumber = 0; + } + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::Commit +// ---------------------------------------------------------------------------- +// +TInt CRsfwPermanentStore::Commit() + { + TInt err = KErrNone; + // Commit writing + if (iFileState == EFileStateWriting) + { + MStreamBuf* streamBuf = iFileWriteStream.Sink(); + err = streamBuf->Synch(); + } + return err; + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::Purge +// ---------------------------------------------------------------------------- +// +TInt CRsfwPermanentStore::Purge() + { + iFileReadStream.Close(); + iFileWriteStream.Close(); + iFile.Close(); + return iFs.Delete(iPath); + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::CompactL +// ---------------------------------------------------------------------------- +// +void CRsfwPermanentStore::CompactL() + { + // Compact the file by dropping empty slots. + // The slot table is also fixed and the free block lists are cleared + // to reflect the new file layout. + + // This function must not be called while the file is opened for reading. + // It is most efficient to call this function before any data is read + // (then there is no slot table to fix) + + // This function must be called before doing GetNextDataL() + // (must be followed by ResetL()). + // However, this function can be called while doing PutDataL(). + + DEBUGSTRING(("CompactL()")); + SetFileStateL(EFileStateClosed); + SetFileStateL(EFileStateReading); + + TBuf dstPath; + dstPath.Copy(iPath); + dstPath.Append('a'); + RFile dstFile; + User::LeaveIfError(dstFile.Replace(iFs, + dstPath, + EFileShareAny | EFileWrite)); + CleanupClosePushL(dstFile); + RFileWriteStream dstFileWriteStream(dstFile); + CleanupClosePushL(dstFileWriteStream); + MStreamBuf* streamBuf = iFileReadStream.Source(); + + // Copy header + dstFileWriteStream.WriteL(iFileReadStream, iFileHeaderSize); + + RArray gaps; + CleanupClosePushL(gaps); + + TInt blockNumber = 0; + TInt lastReadBlockNumber = 0; + TInt nextWriteBlockNumber = 0; + TInt err = KErrNone; + while (err == KErrNone) + { + TSlot gap; + TInt dataLength = 0; + TRAP(err, dataLength = iFileReadStream.ReadInt32L()); + if (err == KErrNone) + { + TInt blockCount; + if (dataLength >= 0) + { + // real data + blockCount = BlockCount(dataLength); +#if 0 + DEBUGSTRING(("Copying at block %d, count %d", + blockNumber, + blockCount)); +#endif + // Back off four bytes + streamBuf->SeekL(MStreamBuf::ERead, + EStreamMark, + -KSlotHeaderSize); + dstFileWriteStream.WriteL(iFileReadStream, + blockCount * iBlockSize); + lastReadBlockNumber = blockNumber; + nextWriteBlockNumber += blockCount; + } + else + { + // empty slot + DEBUGSTRING(("Compacting at block %d", blockNumber)); + blockCount = -dataLength; + streamBuf->SeekL(MStreamBuf::ERead, + EStreamMark, + blockCount * iBlockSize - KSlotHeaderSize); + // Mark block position + gap.iIndex = 0; // not needed here + gap.iBlockNumber = blockNumber; + gap.iBlockCount = blockCount; + gaps.Append(gap); + } + blockNumber += blockCount; + } + } + if (err == KErrEof) + { + err = KErrNone; + } + // Replace old file with the compressed file + SetFileStateL(EFileStateClosed); + dstFileWriteStream.Close(); + dstFile.Close(); + if ((err == KErrNone) && gaps.Count()) + { + // No errors and some compaction was achieved + err = iFs.Delete(iPath); + if (err == KErrNone) + { + err = iFs.Rename(dstPath, iPath); + if (err == KErrNone) + { + DEBUGSTRING(("CompactL(): gaps %d slots %d", + gaps.Count(), + iSlots.Count())); + if (gaps.Count() && iSlots.Count()) + { + // Fix slot table (0(n**2)) + TInt oldBlockNumber = 0; + TInt newBlockNumber = 0; + while (oldBlockNumber <= lastReadBlockNumber) + { + if (gaps.Count()) + { + // still more gaps ... + if (oldBlockNumber == gaps[0].iBlockNumber) + { + oldBlockNumber += gaps[0].iBlockCount; + gaps.Remove(0); + } + } + if (oldBlockNumber != newBlockNumber) + { + FixSlot(oldBlockNumber, newBlockNumber); + } + oldBlockNumber++; + newBlockNumber++; + } + } + } + } + // Clear free block lists + ClearFreeBlockLists(); + // Setup next block to write + iWriteBlockNumber = nextWriteBlockNumber; + } + else + { + // Some error occured or no compaction was achieved + TInt r = iFs.Delete(dstPath); +#ifdef _DEBUG + DEBUGSTRING(("CompactL(): destination file deletion returns %d ", r)); +#endif + } + + CleanupStack::PopAndDestroy(3, &dstFile); // gaps, dstFileWriteStream, dstFile + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::SetHeaderL +// ---------------------------------------------------------------------------- +// +void CRsfwPermanentStore::SetHeaderL(TDesC8& aHeader) + { + delete iFileHeader.iHeader; + iFileHeader.iHeader = NULL; + iFileHeader.iHeader = aHeader.AllocL(); + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::Header +// ---------------------------------------------------------------------------- +// +const HBufC8* CRsfwPermanentStore::Header() + { + if (iFileHeader.iHeader) + { + return iFileHeader.iHeader; + } + else + { + return NULL; + } + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::GetNextDataL +// ---------------------------------------------------------------------------- +// +void CRsfwPermanentStore::GetNextDataL(TUint8* aData, + TInt& aDataLength, + TInt& aIndex) + { + // Return the next slotful of data. + // This function must only be used for sequential access + SetFileStateL(EFileStateReading); + + MStreamBuf* streamBuf = iFileReadStream.Source(); + + TBool done = EFalse; + while (!done) + { + TInt dataLength = 0; + // Eventually leaves with KErrEof + dataLength = iFileReadStream.ReadInt32L(); + TInt blockCount; + if (dataLength >= 0) + { + // Fill data + iFileReadStream.ReadL(aData, dataLength); + aDataLength = dataLength; + aIndex = iIndex; + + // Update block map + blockCount = BlockCount(dataLength); +#if 0 + DEBUGSTRING(( + "GetNextDataL(): index=%d, block=%d, count=%d, len=%d", + iIndex, + iReadBlockNumber, + blockCount, + dataLength)); +#endif + + ReserveSlot(iIndex, iReadBlockNumber, blockCount); + iIndex++; + iReadBlockNumber += blockCount; + + // Update read position to the start of next block + TInt offset = iBlockSize - + (KSlotHeaderSize + dataLength) % iBlockSize; + if (offset != iBlockSize) + { + streamBuf->SeekL(MStreamBuf::ERead, EStreamMark, offset); + } + + done = ETrue; + } + else + { + // Negative length indicates a number of free blocks. + // Put such empty blocks into the free block list + blockCount = -dataLength; + PutToFreeBlockList(iReadBlockNumber, blockCount); + + // Seek to the next slot + streamBuf->SeekL(MStreamBuf::ERead, + EStreamMark, + blockCount * iBlockSize - KSlotHeaderSize); + iReadBlockNumber += blockCount; + } + } + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::PutDataL +// ---------------------------------------------------------------------------- +// +void CRsfwPermanentStore::PutDataL(const TUint8* aData, + TInt aDataLength, + TInt& aIndex) + { + // Write data with the given index + // If the index < 0, this a new data + SetFileStateL(EFileStateWriting); + + if (aDataLength == 0) + { + // We just want to dispose of the slot + ClearSlotL(aIndex); + return; + } + + TBool done = EFalse; + TInt blockCount = BlockCount(aDataLength); + if (aIndex >= 0) + { + // Check if we have space in the existing slot + TSlot* slot = Slot(aIndex); + // We should always find the slot + if (slot) + { + if (slot->iBlockCount == blockCount) + { + // We can use the current slot + WriteBlocksL(aData, aDataLength, slot->iBlockNumber); + done = ETrue; + } + else + { + // Clear the slot + ClearSlotL(aIndex); + } + } + else + { + DEBUGSTRING(("Slot %d not found!", aIndex)); + } + } + else + { + // Allocate new index + aIndex = iIndex++; + } + + if (!done) + { + // Try to get a free slot + TInt blockNumber = GetFromFreeBlockList(blockCount); + if (blockNumber == KErrNotFound) + { + // We have to append to the file + blockNumber = iWriteBlockNumber; + iWriteBlockNumber += blockCount; + } + + ReserveSlot(aIndex, blockNumber, blockCount); + WriteBlocksL(aData, aDataLength, blockNumber); + } + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::BlockCount +// ---------------------------------------------------------------------------- +// +TInt CRsfwPermanentStore::BlockCount(TInt aDataLength) + { + // Get the block count for a given data size + return (KSlotHeaderSize + aDataLength - 1) / iBlockSize + 1; + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::StreamPosition +// ---------------------------------------------------------------------------- +// +TInt CRsfwPermanentStore::StreamPosition(TInt aBlockNumber) + { + // Get the stream position from block position + return (iFileHeaderSize + aBlockNumber * iBlockSize); + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::Slot +// ---------------------------------------------------------------------------- +// +TSlot* CRsfwPermanentStore::Slot(TInt aIndex) + { + // Find the slot with the given index + TSlot slot; // dummy slot for Find() + slot.iIndex = aIndex; + TInt i = iSlots.Find(slot); + if (i != KErrNotFound) + { + return &iSlots[i]; + } + else + { + return NULL; + } + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::FixSlot +// ---------------------------------------------------------------------------- +// +void CRsfwPermanentStore::FixSlot(TInt aOldBlockNumber, TInt aNewBlockNumber) + { + // Assign a new starting block to the slot that used to + // start at aOldBlockNumber. + // The block numbers are changed due to compaction - + // thus the block numbers can only become smaller. + TInt i; + for (i = 0; i < iSlots.Count(); i++) + { + TSlot& slot = iSlots[i]; + // Note that this function can also be called with block numbers + // that do not start a slot - then there will be no match + if (slot.iBlockNumber == aOldBlockNumber) + { + DEBUGSTRING(("Fixing slot %d = %d", + aOldBlockNumber, + aNewBlockNumber)); + slot.iBlockNumber = aNewBlockNumber; + return; + } + } + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::SetFileStateL +// ---------------------------------------------------------------------------- +// +void CRsfwPermanentStore::SetFileStateL(TInt aFileState) + { + DEBUGSTRING(("CRsfwPermanentStore::SetFileStateL")); + DEBUGSTRING(("iFileState = %d, aFileState = %d", iFileState, aFileState)); + if (iFileState != aFileState) + { + switch (iFileState) + { + case EFileStateClosed: + { + if (aFileState == EFileStateReading) + { + DEBUGSTRING(("opening a closed file for reading")); + DEBUGSTRING16(("path is %S", &iPath)); + User::LeaveIfError(iFile.Open(iFs, + iPath, + EFileShareAny | EFileRead)); + TInt size; + iFile.Size(size); + DEBUGSTRING(("opening successfull, file size is %d", size)); + DEBUGSTRING(("header size %d", iFileHeaderSize)); + // sanity + if (size < iFileHeaderSize) + { + // Close the file and leave the file state as "closed" + iFile.Close(); + User::Leave(KErrNotFound); + } + else + { + iFileReadStream.Attach(iFile); + } + } + else + { + // EFileStateWriting + TInt err = iFile.Open(iFs, iPath, EFileShareAny | EFileWrite); + if (err != KErrNone) + { + // The file did not exist + User::LeaveIfError( + iFile.Create(iFs, + iPath, + EFileShareAny | EFileWrite)); + } + TInt size; + User::LeaveIfError(iFile.Size(size)); + iFileWriteStream.Attach(iFile); + if (size < iFileHeaderSize) + { + // Store header if this was a new file + SaveHeaderL(); + } + } + } + break; + + case EFileStateReading: + case EFileStateWriting: + { + // close and redo + if (iFileState == EFileStateReading) + { + iFileReadStream.Close(); + } + else + { + iFileWriteStream.Close(); + } + iFile.Close(); + iFileState = EFileStateClosed; + SetFileStateL(aFileState); + } + break; + + default: + break; + } + + iFileState = aFileState; + } + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::LoadHeaderL +// ---------------------------------------------------------------------------- +// +void CRsfwPermanentStore::LoadHeaderL() + { + DEBUGSTRING(("CRsfwPermanentStore::LoadHeaderL")); + SetFileStateL(EFileStateReading); + iFileHeader.InternalizeL(iFileReadStream); + ResetL(EFalse); + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::SaveHeaderL +// ---------------------------------------------------------------------------- +// +void CRsfwPermanentStore::SaveHeaderL() + { + // Write header with filler + iFileHeader.ExternalizeL(iFileWriteStream); + MStreamBuf* streamBuf = iFileWriteStream.Sink(); + TInt fileHeaderSize = streamBuf->TellL(MStreamBuf::EWrite).Offset(); + TInt residue = iFileHeaderSize - fileHeaderSize; + HBufC8* fill = HBufC8::NewLC(residue); + TPtr8 fillZ = fill->Des(); + fillZ.SetLength(residue); + fillZ.FillZ(); + DEBUGSTRING(("SaveHeader(): header=%d, filler=%d", + iFileHeaderSize, + fillZ.Length())); + iFileWriteStream.WriteL(fillZ); + Commit(); + CleanupStack::PopAndDestroy(fill); // fill + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::ClearFreeBlockLists +// ---------------------------------------------------------------------------- +// +void CRsfwPermanentStore::ClearFreeBlockLists() + { + TInt i; + for (i = 0; i < iFreeBlockLists.Count(); i++) + { + iFreeBlockLists[i].iFreeBlockList.Close(); + } + iFreeBlockLists.Close(); + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::ClearSlotL +// ---------------------------------------------------------------------------- +// +void CRsfwPermanentStore::ClearSlotL(TInt aIndex) + { + // Mark a slot as unused in the file and + // add the slot in the free block list + + TSlot s; // dummy slot for iSlots.Find() + s.iIndex = aIndex; + TInt i = iSlots.Find(s); + if (i != KErrNotFound) + { + TSlot& slot = iSlots[i]; + // Mark the slot in the file as empty + TInt pos = iFileHeaderSize + slot.iBlockNumber * iBlockSize; + + DEBUGSTRING(("ClearSlotL(): index=%d, block=%d, count=%d, pos=%d", + aIndex, + slot.iBlockNumber, + slot.iBlockCount, + pos)); + + MStreamBuf* streamBuf = iFileWriteStream.Sink(); + streamBuf->SeekL(MStreamBuf::EWrite, EStreamBeginning, pos); + iFileWriteStream.WriteInt32L(-slot.iBlockCount); + + // Add the slot in the free block list + PutToFreeBlockList(slot.iBlockNumber, slot.iBlockCount); + + // Delete the slot from the slot table + iSlots.Remove(i); + } + else + { + DEBUGSTRING(("ClearSlotL(): index=%d not found!", aIndex)); + User::Leave(KErrNotFound); + } + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::WriteBlocksL +// ---------------------------------------------------------------------------- +// +void CRsfwPermanentStore::WriteBlocksL(const TUint8* aData, + TInt aDataLength, + TInt aBlockNumber) + { + // Put the given data in the slot specified by the index + TInt pos = iFileHeaderSize + aBlockNumber * iBlockSize; + +#if 0 + DEBUGSTRING(("WriteBlocksL(): block=%d, len=%d, pos=%d", + aBlockNumber, + aDataLength, + pos)); +#endif +#if 0 + TInt size; + iFile.Size(size); + + DEBUGSTRING(("size=%d", size)); +#endif + + MStreamBuf* streamBuf = iFileWriteStream.Sink(); + streamBuf->SeekL(MStreamBuf::EWrite, EStreamBeginning, pos); + + // Write the data in the file (preceded by the length) + iFileWriteStream.WriteInt32L(aDataLength); + iFileWriteStream.WriteL(aData, aDataLength); + + // We have to fill the whole slot if this is the last slot + // in the file. Well, we will will the last bock of all slots + TInt residue = iBlockSize - (KSlotHeaderSize + aDataLength) % iBlockSize; + if (residue != iBlockSize) + { + iFileWriteStream.WriteL(iZeroBlock->Des().Ptr(), residue); + } + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::ReserveSlot +// ---------------------------------------------------------------------------- +// +void CRsfwPermanentStore::ReserveSlot(TInt aIndex, + TInt aBlockNumber, + TInt aBlockCount) + { + TSlot slot; + + slot.iIndex = aIndex; + slot.iBlockNumber = aBlockNumber; + slot.iBlockCount = aBlockCount; + iSlots.Append(slot); + } + + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::PutToFreeBlockList +// ---------------------------------------------------------------------------- +// +void CRsfwPermanentStore::PutToFreeBlockList(TInt aBlockPos, TInt aBlockCount) + { + while (iFreeBlockLists.Count() < aBlockCount) + { + // Construct list until blockCount size + TFreeBlockList freeBlockList; + iFreeBlockLists.Append(freeBlockList); + } + iFreeBlockLists[aBlockCount - 1].iFreeBlockList.Append(aBlockPos); + } + +// ---------------------------------------------------------------------------- +// CRsfwPermanentStore::GetFromFreeBlockList +// ---------------------------------------------------------------------------- +// +TInt CRsfwPermanentStore::GetFromFreeBlockList(TInt aBlockCount) + { + // Only support exact matches. + // That is, bigger slots are not broken into smaller slots + if (iFreeBlockLists.Count() < aBlockCount) + { + // no list + return KErrNotFound; + } + + TFreeBlockList& freeBlockList = iFreeBlockLists[aBlockCount - 1]; + if (freeBlockList.iFreeBlockList.Count() == 0) + { + // no entries in the list + return KErrNotFound; + } + + // Get the first entry in the list + TInt blockPos = freeBlockList.iFreeBlockList[0]; + freeBlockList.iFreeBlockList.Remove(0); + return blockPos; + } + +// End of File