remotestoragefw/remotefileengine/src/rsfwpermanentstore.cpp
changeset 13 6b4fc789785b
parent 2 c32dc0be5eb4
equal deleted inserted replaced
2:c32dc0be5eb4 13:6b4fc789785b
     1 /*
       
     2 * Copyright (c) 2004-2006 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Provides persistent storage for memory blocks
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 // This is a simple block based permanent storage, in which transient
       
    20 // indices are computed on the fly when all data is sequentially read
       
    21 // from the storage.
       
    22 //
       
    23 // The data is put into "slots" that consist of one or more "blocks".
       
    24 // Subsequent updates to the data slots only use the current slot
       
    25 // if the required slot size (block count) has not changed.
       
    26 //
       
    27 // The storage contains a header that may contain any data.
       
    28 // In addition, Each slot contains a header (of type TInt) that
       
    29 // describes the size of the data in the slot.
       
    30 //
       
    31 // The file can be compressed for space efficiency.
       
    32 //
       
    33 // The assumption is that the store is first opened for reading for loading
       
    34 // the data, and then it is only opened for writing until the file is closed.
       
    35 //
       
    36 // (We don't use CRsfwPermanentStore because besides data, we should
       
    37 //  also maintain the indices in a stream of its own)
       
    38 
       
    39 // INCLUDE FILES
       
    40 #include <s32strm.h>
       
    41 #include <s32buf.h>
       
    42 
       
    43 #include "rsfwpermanentstore.h"
       
    44 #include "mdebug.h"
       
    45 
       
    46 
       
    47 // CONSTANTS
       
    48 const TUint KHeaderStart      = 0xbabefade;
       
    49 const TInt  KSlotHeaderSize   = 4;          // sizeof(TInt)
       
    50 const TInt  KDefaultBlockSize = 128;        // default block size in bytes
       
    51 // max value for integer read from the stream, subsequently used to create descriptor
       
    52 const TInt  KMaxDescriptorSize = 16384;         
       
    53 
       
    54 
       
    55 // ============================ MEMBER FUNCTIONS ==============================
       
    56 
       
    57 // ----------------------------------------------------------------------------
       
    58 // TFileHeader::ExternalizeL
       
    59 // ----------------------------------------------------------------------------
       
    60 //
       
    61 void TFileHeader::ExternalizeL(RWriteStream& aStream) const
       
    62     {
       
    63     aStream.WriteInt32L(iHeaderStart);
       
    64     aStream.WriteInt32L(iBlockSize);
       
    65     aStream.WriteInt32L(iHeaderSize);
       
    66     aStream << *iHeader;
       
    67     }
       
    68 
       
    69 // ----------------------------------------------------------------------------
       
    70 // TFileHeader::InternalizeL
       
    71 // ----------------------------------------------------------------------------
       
    72 //
       
    73 void TFileHeader::InternalizeL(RReadStream& aStream)
       
    74     {
       
    75     iHeaderStart = aStream.ReadInt32L();
       
    76     iBlockSize = aStream.ReadInt32L();
       
    77     if (iBlockSize < 0 || iBlockSize > KMaxDescriptorSize)
       
    78         {
       
    79         User::Leave(KErrCorrupt);
       
    80         }    
       
    81     iHeaderSize = aStream.ReadInt32L();
       
    82     if (iHeaderSize < 0 || iHeaderSize > KMaxDescriptorSize)
       
    83         {
       
    84         User::Leave(KErrCorrupt);
       
    85         }     
       
    86     iHeader = HBufC8::NewL(aStream, iHeaderSize);
       
    87     }
       
    88 
       
    89 // ----------------------------------------------------------------------------
       
    90 // CRsfwPermanentStore::NewL
       
    91 // ----------------------------------------------------------------------------
       
    92 //
       
    93 CRsfwPermanentStore* CRsfwPermanentStore::NewL(const TDesC& aPath,
       
    94                                        TInt aHeaderSize,
       
    95                                        TInt aBlockSize)
       
    96     {
       
    97     CRsfwPermanentStore* self = new (ELeave) CRsfwPermanentStore();
       
    98     CleanupStack::PushL(self);
       
    99     self->ConstructL(aPath, aHeaderSize, aBlockSize);
       
   100     CleanupStack::Pop(self);
       
   101     return self;
       
   102     }
       
   103 
       
   104 // ----------------------------------------------------------------------------
       
   105 // CRsfwPermanentStore::~CRsfwPermanentStore
       
   106 // ----------------------------------------------------------------------------
       
   107 //
       
   108 CRsfwPermanentStore::~CRsfwPermanentStore()
       
   109     {
       
   110     ClearFreeBlockLists();
       
   111     iSlots.Close();
       
   112     iFileReadStream.Close();
       
   113     iFileWriteStream.Close();
       
   114     iFile.Close();
       
   115     iFs.Close();
       
   116     delete iFileHeader.iHeader;
       
   117     delete iZeroBlock;
       
   118     }
       
   119 
       
   120 // ----------------------------------------------------------------------------
       
   121 // CRsfwPermanentStore::ConstructL
       
   122 // ----------------------------------------------------------------------------
       
   123 //
       
   124 void CRsfwPermanentStore::ConstructL(const TDesC& aPath,
       
   125                                  TInt aHeaderSize,
       
   126                                  TInt aBlockSize)
       
   127     {
       
   128     DEBUGSTRING(("CRsfwPermanentStore::ConstructL()"));
       
   129     User::LeaveIfError(iFs.Connect());
       
   130     iPath.Copy(aPath);
       
   131 
       
   132     iHeaderSize = aHeaderSize;
       
   133     // Offset to the block data
       
   134     iFileHeaderSize = iHeaderSize + sizeof(TFileHeader);
       
   135     TRAPD(err, LoadHeaderL());
       
   136     if (err == KErrNone)
       
   137         {
       
   138         // Read parameters from the existing file, if any
       
   139         iHeaderSize = iFileHeader.iHeaderSize;
       
   140         iBlockSize = iFileHeader.iBlockSize;
       
   141         }
       
   142     else
       
   143         {
       
   144         // There was no existing file
       
   145         DEBUGSTRING(("LoadHeaderL returns %d", err));
       
   146         if (aBlockSize)
       
   147             {
       
   148             iBlockSize = aBlockSize;
       
   149             }
       
   150         else
       
   151             {
       
   152             iBlockSize = KDefaultBlockSize;
       
   153             }
       
   154         iFileHeader.iHeaderStart = KHeaderStart;
       
   155         iFileHeader.iHeaderSize = iHeaderSize;
       
   156         iFileHeader.iBlockSize = iBlockSize;
       
   157         }
       
   158     // Compute the offset to data blocks
       
   159     // (this is 4 bytes too many but that is OK ...)
       
   160     iFileHeaderSize = iHeaderSize + sizeof(TFileHeader);
       
   161     // Make a block of zeroes
       
   162     iZeroBlock = HBufC8::NewL(iBlockSize);
       
   163     iZeroBlock->Des().FillZ();
       
   164     DEBUGSTRING(("ConstructL() done, blocksize=%d", iBlockSize));
       
   165     }
       
   166 
       
   167 // ----------------------------------------------------------------------------
       
   168 // CRsfwPermanentStore::ResetL
       
   169 // ----------------------------------------------------------------------------
       
   170 //
       
   171 void CRsfwPermanentStore::ResetL(TBool aWriting)
       
   172     {
       
   173     // This function is called by the client
       
   174     // before starting to read or write data slots
       
   175     if (aWriting)
       
   176         {
       
   177         SetFileStateL(EFileStateWriting);
       
   178         // Set write pointer to the end of the file
       
   179         MStreamBuf* streamBuf = iFileWriteStream.Sink();
       
   180         TInt size = streamBuf->SizeL();
       
   181         iWriteBlockNumber = (size - iFileHeaderSize) / iBlockSize;
       
   182         if ((iWriteBlockNumber * iBlockSize) != (size - iFileHeaderSize))
       
   183             {
       
   184             DEBUGSTRING(("ResetL(): file size incorrect (%d)",
       
   185                          size));
       
   186             }
       
   187         }
       
   188     else
       
   189         {
       
   190         // reading
       
   191         SetFileStateL(EFileStateReading);
       
   192         // Skip file header
       
   193         MStreamBuf* streamBuf = iFileReadStream.Source();
       
   194         streamBuf->SeekL(MStreamBuf::ERead,
       
   195                          EStreamBeginning,
       
   196                          iFileHeaderSize);
       
   197         iReadBlockNumber = 0;
       
   198         }
       
   199     }
       
   200 
       
   201 // ----------------------------------------------------------------------------
       
   202 // CRsfwPermanentStore::Commit
       
   203 // ----------------------------------------------------------------------------
       
   204 //
       
   205 TInt CRsfwPermanentStore::Commit()
       
   206     {
       
   207     TInt err = KErrNone;
       
   208     // Commit writing
       
   209     if (iFileState == EFileStateWriting)
       
   210         {
       
   211         MStreamBuf* streamBuf = iFileWriteStream.Sink();
       
   212         err = streamBuf->Synch();
       
   213         }
       
   214     return err;
       
   215     }
       
   216 
       
   217 // ----------------------------------------------------------------------------
       
   218 // CRsfwPermanentStore::Purge
       
   219 // ----------------------------------------------------------------------------
       
   220 //
       
   221 TInt CRsfwPermanentStore::Purge()
       
   222     {
       
   223     iFileReadStream.Close();
       
   224     iFileWriteStream.Close();
       
   225     iFile.Close();
       
   226     return iFs.Delete(iPath);
       
   227     }
       
   228 
       
   229 // ----------------------------------------------------------------------------
       
   230 // CRsfwPermanentStore::CompactL
       
   231 // ----------------------------------------------------------------------------
       
   232 //
       
   233 void CRsfwPermanentStore::CompactL()
       
   234     {
       
   235     // Compact the file by dropping empty slots.
       
   236     // The slot table is also fixed and the free block lists are cleared
       
   237     // to reflect the new file layout.
       
   238 
       
   239     // This function must not be called while the file is opened for reading.
       
   240     // It is most efficient to call this function before any data is read
       
   241     // (then there is no slot table to fix)
       
   242 
       
   243     // This function must be called before doing GetNextDataL()
       
   244     // (must be followed by ResetL()).
       
   245     // However, this function can be called while doing PutDataL(). 
       
   246 
       
   247     DEBUGSTRING(("CompactL()"));
       
   248     SetFileStateL(EFileStateClosed);
       
   249     SetFileStateL(EFileStateReading);
       
   250     
       
   251     TBuf<KMaxPath> dstPath;
       
   252     dstPath.Copy(iPath);
       
   253     dstPath.Append('a');
       
   254     RFile dstFile;
       
   255     User::LeaveIfError(dstFile.Replace(iFs,
       
   256                                        dstPath,
       
   257                                        EFileShareAny | EFileWrite));
       
   258     CleanupClosePushL(dstFile);
       
   259     RFileWriteStream dstFileWriteStream(dstFile);
       
   260     CleanupClosePushL(dstFileWriteStream);
       
   261     MStreamBuf* streamBuf = iFileReadStream.Source();
       
   262 
       
   263     // Copy header
       
   264     dstFileWriteStream.WriteL(iFileReadStream, iFileHeaderSize);
       
   265 
       
   266     RArray<TSlot> gaps;
       
   267     CleanupClosePushL(gaps);
       
   268 
       
   269     TInt blockNumber = 0;
       
   270     TInt lastReadBlockNumber = 0;
       
   271     TInt nextWriteBlockNumber = 0;
       
   272     TInt err = KErrNone;
       
   273     while (err == KErrNone)
       
   274         {
       
   275         TSlot gap;
       
   276         TInt dataLength = 0;
       
   277         TRAP(err, dataLength = iFileReadStream.ReadInt32L());
       
   278         if (err == KErrNone)
       
   279             {
       
   280             TInt blockCount;
       
   281             if (dataLength >= 0)
       
   282                 {
       
   283                 // real data
       
   284                 blockCount = BlockCount(dataLength);
       
   285 #if 0
       
   286                 DEBUGSTRING(("Copying at block %d, count %d",
       
   287                              blockNumber,
       
   288                              blockCount));
       
   289 #endif
       
   290                 // Back off four bytes
       
   291                 streamBuf->SeekL(MStreamBuf::ERead,
       
   292                                  EStreamMark,
       
   293                                  -KSlotHeaderSize);
       
   294                 dstFileWriteStream.WriteL(iFileReadStream,
       
   295                                           blockCount * iBlockSize);
       
   296                 lastReadBlockNumber = blockNumber;
       
   297                 nextWriteBlockNumber += blockCount;
       
   298                 }
       
   299             else
       
   300                 {
       
   301                 // empty slot
       
   302                 DEBUGSTRING(("Compacting at block %d", blockNumber));
       
   303                 blockCount = -dataLength;
       
   304                 streamBuf->SeekL(MStreamBuf::ERead,
       
   305                                  EStreamMark,
       
   306                                  blockCount * iBlockSize - KSlotHeaderSize);
       
   307                 // Mark block position
       
   308                 gap.iIndex = 0;  // not needed here
       
   309                 gap.iBlockNumber = blockNumber;
       
   310                 gap.iBlockCount = blockCount;
       
   311                 gaps.Append(gap);
       
   312                 }
       
   313             blockNumber += blockCount;
       
   314             }
       
   315         }
       
   316     if (err == KErrEof)
       
   317         {
       
   318         err = KErrNone;
       
   319         }
       
   320     // Replace old file with the compressed file
       
   321     SetFileStateL(EFileStateClosed);
       
   322     dstFileWriteStream.Close();
       
   323     dstFile.Close();
       
   324     if ((err == KErrNone) && gaps.Count())
       
   325         {
       
   326         // No errors and some compaction was achieved
       
   327         err = iFs.Delete(iPath);
       
   328         if (err == KErrNone)
       
   329             {
       
   330             err = iFs.Rename(dstPath, iPath);
       
   331             if (err == KErrNone)
       
   332                 {
       
   333                 DEBUGSTRING(("CompactL(): gaps %d slots %d",
       
   334                              gaps.Count(),
       
   335                              iSlots.Count()));
       
   336                 if (gaps.Count() && iSlots.Count())
       
   337                     {
       
   338                     // Fix slot table (0(n**2))
       
   339                     TInt oldBlockNumber = 0;
       
   340                     TInt newBlockNumber = 0;
       
   341                     while (oldBlockNumber <= lastReadBlockNumber)
       
   342                         {
       
   343                         if (gaps.Count())
       
   344                             {
       
   345                             // still more gaps ...
       
   346                             if (oldBlockNumber == gaps[0].iBlockNumber)
       
   347                                 {
       
   348                                 oldBlockNumber += gaps[0].iBlockCount;
       
   349                                 gaps.Remove(0);
       
   350                                 }
       
   351                             }
       
   352                         if (oldBlockNumber != newBlockNumber)
       
   353                             {
       
   354                             FixSlot(oldBlockNumber, newBlockNumber);
       
   355                             }
       
   356                         oldBlockNumber++;
       
   357                         newBlockNumber++;
       
   358                         }
       
   359                     }
       
   360                 }
       
   361             }
       
   362         // Clear free block lists
       
   363         ClearFreeBlockLists();
       
   364         // Setup next block to write
       
   365         iWriteBlockNumber = nextWriteBlockNumber;
       
   366         }
       
   367     else
       
   368         {
       
   369         // Some error occured or no compaction was achieved
       
   370         TInt r = iFs.Delete(dstPath);
       
   371 #ifdef _DEBUG
       
   372         DEBUGSTRING(("CompactL(): destination file deletion returns %d ", r));
       
   373 #endif
       
   374         }
       
   375 
       
   376     CleanupStack::PopAndDestroy(3, &dstFile); // gaps, dstFileWriteStream, dstFile
       
   377     }
       
   378 
       
   379 // ----------------------------------------------------------------------------
       
   380 // CRsfwPermanentStore::SetHeaderL
       
   381 // ----------------------------------------------------------------------------
       
   382 //
       
   383 void CRsfwPermanentStore::SetHeaderL(TDesC8& aHeader)
       
   384     {
       
   385     delete iFileHeader.iHeader;
       
   386     iFileHeader.iHeader = NULL;
       
   387     iFileHeader.iHeader = aHeader.AllocL();
       
   388     }
       
   389 
       
   390 // ----------------------------------------------------------------------------
       
   391 // CRsfwPermanentStore::Header
       
   392 // ----------------------------------------------------------------------------
       
   393 //
       
   394 const HBufC8* CRsfwPermanentStore::Header()
       
   395     {
       
   396     if (iFileHeader.iHeader)
       
   397         {
       
   398         return iFileHeader.iHeader;
       
   399         }
       
   400     else
       
   401         {
       
   402         return NULL;
       
   403         }
       
   404     }
       
   405 
       
   406 // ----------------------------------------------------------------------------
       
   407 // CRsfwPermanentStore::GetNextDataL
       
   408 // ----------------------------------------------------------------------------
       
   409 //
       
   410 void CRsfwPermanentStore::GetNextDataL(TUint8* aData,
       
   411                                    TInt& aDataLength,
       
   412                                    TInt& aIndex)
       
   413     {
       
   414     // Return the next slotful of data.
       
   415     // This function must only be used for sequential access
       
   416     SetFileStateL(EFileStateReading);
       
   417 
       
   418     MStreamBuf* streamBuf = iFileReadStream.Source();
       
   419     
       
   420     TBool done = EFalse;
       
   421     while (!done)
       
   422         {
       
   423         TInt dataLength = 0;
       
   424         // Eventually leaves with KErrEof
       
   425         dataLength = iFileReadStream.ReadInt32L();
       
   426         TInt blockCount;
       
   427         if (dataLength >= 0)
       
   428             {
       
   429             // Fill data
       
   430             iFileReadStream.ReadL(aData, dataLength);
       
   431             aDataLength = dataLength;
       
   432             aIndex = iIndex;
       
   433 
       
   434             // Update block map
       
   435             blockCount = BlockCount(dataLength);
       
   436 #if 0
       
   437             DEBUGSTRING((
       
   438                             "GetNextDataL(): index=%d, block=%d, count=%d, len=%d",
       
   439                             iIndex,
       
   440                             iReadBlockNumber,
       
   441                             blockCount,
       
   442                             dataLength));
       
   443 #endif
       
   444 
       
   445             ReserveSlot(iIndex, iReadBlockNumber, blockCount); 
       
   446             iIndex++;
       
   447             iReadBlockNumber += blockCount;
       
   448 
       
   449             // Update read position to the start of next block
       
   450             TInt offset = iBlockSize -
       
   451                 (KSlotHeaderSize + dataLength) % iBlockSize;
       
   452             if (offset != iBlockSize)
       
   453                 {
       
   454                 streamBuf->SeekL(MStreamBuf::ERead, EStreamMark, offset);
       
   455                 }
       
   456             
       
   457             done = ETrue;
       
   458             }
       
   459         else
       
   460             {
       
   461             // Negative length indicates a number of free blocks.
       
   462             // Put such empty blocks into the free block list
       
   463             blockCount = -dataLength;
       
   464             PutToFreeBlockList(iReadBlockNumber, blockCount);
       
   465             
       
   466             // Seek to the next slot
       
   467             streamBuf->SeekL(MStreamBuf::ERead, 
       
   468                              EStreamMark,
       
   469                              blockCount * iBlockSize - KSlotHeaderSize);
       
   470             iReadBlockNumber += blockCount;
       
   471             }
       
   472         }
       
   473     }
       
   474 
       
   475 // ----------------------------------------------------------------------------
       
   476 // CRsfwPermanentStore::PutDataL
       
   477 // ----------------------------------------------------------------------------
       
   478 //
       
   479 void CRsfwPermanentStore::PutDataL(const TUint8* aData,
       
   480                                TInt aDataLength,
       
   481                                TInt& aIndex)
       
   482     {
       
   483     // Write data with the given index
       
   484     // If the index < 0, this a new data
       
   485     SetFileStateL(EFileStateWriting);
       
   486 
       
   487     if (aDataLength == 0)
       
   488         {
       
   489         // We just want to dispose of the slot
       
   490         ClearSlotL(aIndex);
       
   491         return;
       
   492         }
       
   493 
       
   494     TBool done = EFalse;
       
   495     TInt blockCount = BlockCount(aDataLength);
       
   496     if (aIndex >= 0)
       
   497         {
       
   498         // Check if we have space in the existing slot
       
   499         TSlot* slot = Slot(aIndex);
       
   500         // We should always find the slot
       
   501         if (slot)
       
   502             {
       
   503             if (slot->iBlockCount == blockCount)
       
   504                 {
       
   505                 // We can use the current slot
       
   506                 WriteBlocksL(aData, aDataLength, slot->iBlockNumber);
       
   507                 done = ETrue;
       
   508                 }
       
   509             else
       
   510                 {
       
   511                 // Clear the slot
       
   512                 ClearSlotL(aIndex);
       
   513                 }
       
   514             }
       
   515         else
       
   516             {
       
   517             DEBUGSTRING(("Slot %d not found!", aIndex));
       
   518             }
       
   519         }
       
   520     else
       
   521         {
       
   522         // Allocate new index
       
   523         aIndex = iIndex++;
       
   524         }
       
   525     
       
   526     if (!done)
       
   527         {
       
   528         // Try to get a free slot
       
   529         TInt blockNumber = GetFromFreeBlockList(blockCount);
       
   530         if (blockNumber == KErrNotFound)
       
   531             {
       
   532             // We have to append to the file
       
   533             blockNumber = iWriteBlockNumber;
       
   534             iWriteBlockNumber += blockCount;
       
   535             }
       
   536         
       
   537         ReserveSlot(aIndex, blockNumber, blockCount);
       
   538         WriteBlocksL(aData, aDataLength, blockNumber);
       
   539         }
       
   540     }
       
   541 
       
   542 // ----------------------------------------------------------------------------
       
   543 // CRsfwPermanentStore::BlockCount
       
   544 // ----------------------------------------------------------------------------
       
   545 //
       
   546 TInt CRsfwPermanentStore::BlockCount(TInt aDataLength)
       
   547     {
       
   548     // Get the block count for a given data size
       
   549     return (KSlotHeaderSize + aDataLength - 1) / iBlockSize + 1;
       
   550     }
       
   551 
       
   552 // ----------------------------------------------------------------------------
       
   553 // CRsfwPermanentStore::StreamPosition
       
   554 // ----------------------------------------------------------------------------
       
   555 //
       
   556 TInt CRsfwPermanentStore::StreamPosition(TInt aBlockNumber)
       
   557     {
       
   558     // Get the stream position from block position
       
   559     return (iFileHeaderSize + aBlockNumber * iBlockSize);
       
   560     }
       
   561 
       
   562 // ----------------------------------------------------------------------------
       
   563 // CRsfwPermanentStore::Slot
       
   564 // ----------------------------------------------------------------------------
       
   565 //
       
   566 TSlot* CRsfwPermanentStore::Slot(TInt aIndex)
       
   567     {
       
   568     // Find the slot with the given index
       
   569     TSlot slot;             // dummy slot for Find()
       
   570     slot.iIndex = aIndex;
       
   571     TInt i = iSlots.Find(slot);
       
   572     if (i != KErrNotFound)
       
   573         {
       
   574         return &iSlots[i];
       
   575         }
       
   576     else
       
   577         {
       
   578         return NULL;
       
   579         }
       
   580     }
       
   581 
       
   582 // ----------------------------------------------------------------------------
       
   583 // CRsfwPermanentStore::FixSlot
       
   584 // ----------------------------------------------------------------------------
       
   585 //
       
   586 void CRsfwPermanentStore::FixSlot(TInt aOldBlockNumber, TInt aNewBlockNumber)
       
   587     {
       
   588     // Assign a new starting block to the slot that used to
       
   589     // start at aOldBlockNumber.
       
   590     // The block numbers are changed due to compaction -
       
   591     // thus the block numbers can only become smaller.
       
   592     TInt i;
       
   593     for (i = 0; i < iSlots.Count(); i++)
       
   594         {
       
   595         TSlot& slot = iSlots[i];
       
   596         // Note that this function can also be called with block numbers
       
   597         // that do not start a slot - then there will be no match
       
   598         if (slot.iBlockNumber == aOldBlockNumber)
       
   599             {
       
   600             DEBUGSTRING(("Fixing slot %d = %d",
       
   601                          aOldBlockNumber,
       
   602                          aNewBlockNumber));
       
   603             slot.iBlockNumber = aNewBlockNumber;
       
   604             return;
       
   605             }
       
   606         }
       
   607     }
       
   608 
       
   609 // ----------------------------------------------------------------------------
       
   610 // CRsfwPermanentStore::SetFileStateL
       
   611 // ----------------------------------------------------------------------------
       
   612 //
       
   613 void CRsfwPermanentStore::SetFileStateL(TInt aFileState)
       
   614     {
       
   615     DEBUGSTRING(("CRsfwPermanentStore::SetFileStateL"));
       
   616     DEBUGSTRING(("iFileState = %d, aFileState = %d", iFileState, aFileState));
       
   617     if (iFileState != aFileState)
       
   618         {
       
   619         switch (iFileState)
       
   620             {
       
   621         case EFileStateClosed:
       
   622             {
       
   623             if (aFileState == EFileStateReading)
       
   624                 {
       
   625                 DEBUGSTRING(("opening a closed file for reading"));
       
   626                 DEBUGSTRING16(("path is %S", &iPath));
       
   627                 User::LeaveIfError(iFile.Open(iFs,
       
   628                                               iPath,
       
   629                                               EFileShareAny | EFileRead));
       
   630                 TInt size;
       
   631                 iFile.Size(size);
       
   632                 DEBUGSTRING(("opening successfull, file size is %d", size));
       
   633                 DEBUGSTRING(("header size %d", iFileHeaderSize));
       
   634                 // sanity
       
   635                 if (size < iFileHeaderSize)
       
   636                     {
       
   637                     // Close the file and leave the file state as "closed"
       
   638                     iFile.Close();
       
   639                     User::Leave(KErrNotFound);
       
   640                     }
       
   641                 else
       
   642                     {
       
   643                     iFileReadStream.Attach(iFile);
       
   644                     }
       
   645                 }
       
   646             else
       
   647                 {
       
   648                 // EFileStateWriting
       
   649                 TInt err = iFile.Open(iFs, iPath, EFileShareAny | EFileWrite);
       
   650                 if (err != KErrNone)
       
   651                     {
       
   652                     // The file did not exist
       
   653                     User::LeaveIfError(
       
   654                         iFile.Create(iFs,
       
   655                                      iPath,
       
   656                                      EFileShareAny | EFileWrite));
       
   657                     }
       
   658                 TInt size;
       
   659                 User::LeaveIfError(iFile.Size(size));
       
   660                 iFileWriteStream.Attach(iFile);
       
   661                 if (size < iFileHeaderSize)
       
   662                     {
       
   663                     // Store header if this was a new file
       
   664                     SaveHeaderL();
       
   665                     }
       
   666                 }
       
   667             }
       
   668             break;
       
   669         
       
   670         case EFileStateReading:
       
   671         case EFileStateWriting:
       
   672             {
       
   673             // close and redo
       
   674             if (iFileState == EFileStateReading)
       
   675                 {
       
   676                 iFileReadStream.Close();
       
   677                 }
       
   678             else
       
   679                 {
       
   680                 iFileWriteStream.Close();
       
   681                 }
       
   682             iFile.Close();
       
   683             iFileState = EFileStateClosed;
       
   684             SetFileStateL(aFileState);
       
   685             }
       
   686             break;
       
   687     
       
   688         default:
       
   689             break;
       
   690             }
       
   691         
       
   692         iFileState = aFileState;
       
   693         }
       
   694     }
       
   695 
       
   696 // ----------------------------------------------------------------------------
       
   697 // CRsfwPermanentStore::LoadHeaderL
       
   698 // ----------------------------------------------------------------------------
       
   699 //
       
   700 void CRsfwPermanentStore::LoadHeaderL()
       
   701     {
       
   702     DEBUGSTRING(("CRsfwPermanentStore::LoadHeaderL"));
       
   703     SetFileStateL(EFileStateReading);
       
   704     iFileHeader.InternalizeL(iFileReadStream);
       
   705     ResetL(EFalse);
       
   706     }
       
   707 
       
   708 // ----------------------------------------------------------------------------
       
   709 // CRsfwPermanentStore::SaveHeaderL
       
   710 // ----------------------------------------------------------------------------
       
   711 //
       
   712 void CRsfwPermanentStore::SaveHeaderL()
       
   713     {
       
   714     // Write header with filler
       
   715     iFileHeader.ExternalizeL(iFileWriteStream);
       
   716     MStreamBuf* streamBuf = iFileWriteStream.Sink();
       
   717     TInt fileHeaderSize = streamBuf->TellL(MStreamBuf::EWrite).Offset();
       
   718     TInt residue = iFileHeaderSize - fileHeaderSize;
       
   719     HBufC8* fill = HBufC8::NewLC(residue);
       
   720     TPtr8 fillZ = fill->Des();
       
   721     fillZ.SetLength(residue);
       
   722     fillZ.FillZ();
       
   723     DEBUGSTRING(("SaveHeader(): header=%d, filler=%d",
       
   724                  iFileHeaderSize,
       
   725                  fillZ.Length()));
       
   726     iFileWriteStream.WriteL(fillZ);
       
   727     Commit();
       
   728     CleanupStack::PopAndDestroy(fill); // fill
       
   729     }
       
   730 
       
   731 // ----------------------------------------------------------------------------
       
   732 // CRsfwPermanentStore::ClearFreeBlockLists
       
   733 // ----------------------------------------------------------------------------
       
   734 //
       
   735 void CRsfwPermanentStore::ClearFreeBlockLists()
       
   736     {
       
   737     TInt i;
       
   738     for (i = 0; i < iFreeBlockLists.Count(); i++)
       
   739         {
       
   740         iFreeBlockLists[i].iFreeBlockList.Close();
       
   741         }
       
   742     iFreeBlockLists.Close();
       
   743     }
       
   744 
       
   745 // ----------------------------------------------------------------------------
       
   746 // CRsfwPermanentStore::ClearSlotL
       
   747 // ----------------------------------------------------------------------------
       
   748 //
       
   749 void CRsfwPermanentStore::ClearSlotL(TInt aIndex)
       
   750     {
       
   751     // Mark a slot as unused in the file and
       
   752     // add the slot in the free block list
       
   753 
       
   754     TSlot s;                // dummy slot for iSlots.Find()
       
   755     s.iIndex = aIndex;
       
   756     TInt i = iSlots.Find(s);
       
   757     if (i != KErrNotFound)
       
   758         {
       
   759         TSlot& slot = iSlots[i];
       
   760         // Mark the slot in the file as empty
       
   761         TInt pos = iFileHeaderSize +  slot.iBlockNumber * iBlockSize;
       
   762 
       
   763         DEBUGSTRING(("ClearSlotL(): index=%d, block=%d, count=%d, pos=%d",
       
   764                      aIndex,
       
   765                      slot.iBlockNumber,
       
   766                      slot.iBlockCount,
       
   767                      pos));
       
   768 
       
   769         MStreamBuf* streamBuf = iFileWriteStream.Sink();
       
   770         streamBuf->SeekL(MStreamBuf::EWrite, EStreamBeginning, pos);
       
   771         iFileWriteStream.WriteInt32L(-slot.iBlockCount);
       
   772         
       
   773         // Add the slot in the free block list
       
   774         PutToFreeBlockList(slot.iBlockNumber, slot.iBlockCount);
       
   775 
       
   776         // Delete the slot from the slot table
       
   777         iSlots.Remove(i);
       
   778         }
       
   779     else
       
   780         {
       
   781         DEBUGSTRING(("ClearSlotL(): index=%d not found!", aIndex));
       
   782         User::Leave(KErrNotFound);
       
   783         }
       
   784     }
       
   785 
       
   786 // ----------------------------------------------------------------------------
       
   787 // CRsfwPermanentStore::WriteBlocksL
       
   788 // ----------------------------------------------------------------------------
       
   789 //
       
   790 void CRsfwPermanentStore::WriteBlocksL(const TUint8* aData,
       
   791                                    TInt aDataLength,
       
   792                                    TInt aBlockNumber)
       
   793     {
       
   794     // Put the given data in the slot specified by the index
       
   795     TInt pos = iFileHeaderSize +  aBlockNumber * iBlockSize;
       
   796 
       
   797 #if 0
       
   798     DEBUGSTRING(("WriteBlocksL(): block=%d, len=%d, pos=%d",
       
   799                  aBlockNumber,
       
   800                  aDataLength,
       
   801                  pos));
       
   802 #endif
       
   803 #if 0
       
   804     TInt size;
       
   805     iFile.Size(size);
       
   806 
       
   807     DEBUGSTRING(("size=%d", size));
       
   808 #endif
       
   809     
       
   810     MStreamBuf* streamBuf = iFileWriteStream.Sink();
       
   811     streamBuf->SeekL(MStreamBuf::EWrite, EStreamBeginning, pos);
       
   812     
       
   813     // Write the data in the file (preceded by the length)
       
   814     iFileWriteStream.WriteInt32L(aDataLength);
       
   815     iFileWriteStream.WriteL(aData, aDataLength);
       
   816 
       
   817     // We have to fill the whole slot if this is the last slot
       
   818     // in the file. Well, we will will the last bock of all slots
       
   819     TInt residue = iBlockSize - (KSlotHeaderSize + aDataLength) % iBlockSize;
       
   820     if (residue != iBlockSize)
       
   821         {
       
   822         iFileWriteStream.WriteL(iZeroBlock->Des().Ptr(), residue);
       
   823         }
       
   824     }
       
   825 
       
   826 // ----------------------------------------------------------------------------
       
   827 // CRsfwPermanentStore::ReserveSlot
       
   828 // ----------------------------------------------------------------------------
       
   829 //
       
   830 void CRsfwPermanentStore::ReserveSlot(TInt aIndex,
       
   831                                   TInt aBlockNumber,
       
   832                                   TInt aBlockCount)
       
   833     {
       
   834     TSlot slot;
       
   835 
       
   836     slot.iIndex = aIndex;
       
   837     slot.iBlockNumber = aBlockNumber;
       
   838     slot.iBlockCount = aBlockCount;
       
   839     iSlots.Append(slot);
       
   840     }
       
   841 
       
   842 
       
   843 // ----------------------------------------------------------------------------
       
   844 // CRsfwPermanentStore::PutToFreeBlockList
       
   845 // ----------------------------------------------------------------------------
       
   846 //
       
   847 void CRsfwPermanentStore::PutToFreeBlockList(TInt aBlockPos, TInt aBlockCount)
       
   848     {
       
   849     while (iFreeBlockLists.Count() < aBlockCount)
       
   850         {
       
   851         // Construct list until blockCount size
       
   852         TFreeBlockList freeBlockList;
       
   853         iFreeBlockLists.Append(freeBlockList);
       
   854         }
       
   855     iFreeBlockLists[aBlockCount - 1].iFreeBlockList.Append(aBlockPos);
       
   856     }
       
   857 
       
   858 // ----------------------------------------------------------------------------
       
   859 // CRsfwPermanentStore::GetFromFreeBlockList
       
   860 // ----------------------------------------------------------------------------
       
   861 //
       
   862 TInt CRsfwPermanentStore::GetFromFreeBlockList(TInt aBlockCount)
       
   863     {
       
   864     // Only support exact matches.
       
   865     // That is, bigger slots are not broken into smaller slots
       
   866     if (iFreeBlockLists.Count() < aBlockCount)
       
   867         {
       
   868         // no list
       
   869         return KErrNotFound;
       
   870         }
       
   871 
       
   872     TFreeBlockList& freeBlockList = iFreeBlockLists[aBlockCount - 1]; 
       
   873     if (freeBlockList.iFreeBlockList.Count() == 0)
       
   874         {
       
   875         // no entries in the list
       
   876         return KErrNotFound;
       
   877         }
       
   878 
       
   879     // Get the first entry in the list
       
   880     TInt blockPos = freeBlockList.iFreeBlockList[0];
       
   881     freeBlockList.iFreeBlockList.Remove(0);
       
   882     return blockPos;
       
   883     }
       
   884 
       
   885 // End of File