--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/remotestoragefw/remotefileengine/src/rsfwpermanentstore.cpp Thu Dec 17 09:07:59 2009 +0200
@@ -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 <s32strm.h>
+#include <s32buf.h>
+
+#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<KMaxPath> 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<TSlot> 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