remotestoragefw/remotefileengine/src/rsfwfiletable.cpp
changeset 13 6b4fc789785b
parent 2 c32dc0be5eb4
equal deleted inserted replaced
2:c32dc0be5eb4 13:6b4fc789785b
     1 /*
       
     2 * Copyright (c) 2003-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:  metadata struct for remote files
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include <s32mem.h>
       
    20 
       
    21 #include "rsfwfiletable.h"
       
    22 #include "rsfwfileentry.h"
       
    23 #include "rsfwfileengine.h"
       
    24 #include "rsfwvolumetable.h"
       
    25 #include "rsfwvolume.h"
       
    26 #include "rsfwrfeserver.h"
       
    27 #include "rsfwwaitnotemanager.h"
       
    28 #include "mdebug.h"
       
    29 
       
    30 
       
    31 // ----------------------------------------------------------------------------
       
    32 // CRsfwFileTable::NewL
       
    33 // ----------------------------------------------------------------------------
       
    34 //   
       
    35 CRsfwFileTable* CRsfwFileTable::NewL(CRsfwVolume* aVolume, TFileName& aCachePath)
       
    36     {
       
    37     CRsfwFileTable* self = new (ELeave) CRsfwFileTable();
       
    38     DEBUGSTRING(("CRsfwFileTable: in NewL 0x%x", self));
       
    39     CleanupStack::PushL(self);
       
    40     self->ConstructL(aVolume, aCachePath);
       
    41     CleanupStack::Pop(self);
       
    42     return self;
       
    43     }
       
    44 
       
    45 // ----------------------------------------------------------------------------
       
    46 // CRsfwFileTable::ConstructL
       
    47 // ----------------------------------------------------------------------------
       
    48 //   
       
    49 void CRsfwFileTable::ConstructL(CRsfwVolume* aVolume, TFileName& aCachePath)
       
    50     {
       
    51     iFs = CRsfwRfeServer::Env()->iFs;
       
    52     // The root will be number 1
       
    53     iNodeId = 1;
       
    54     iVolume = aVolume;
       
    55     iRootFep = NULL;
       
    56     iCachePath.Copy(aCachePath);
       
    57     iPermanence = iVolume->iMountInfo.iMountStatus.iPermanence;
       
    58     iMetaDataFilePath.Copy(aCachePath);
       
    59     iMetaDataFilePath.Append(KMetaDataFileName);
       
    60     iMetaDataEvents.Reset();
       
    61     SetupCacheL();
       
    62     }
       
    63 
       
    64 // ----------------------------------------------------------------------------
       
    65 // CRsfwFileTable::~CRsfwFileTable
       
    66 // ----------------------------------------------------------------------------
       
    67 //   
       
    68 CRsfwFileTable::~CRsfwFileTable()
       
    69     {
       
    70     if (iRootFep)
       
    71         {
       
    72         // Delete the whole tree recursively
       
    73         delete iRootFep;
       
    74         iRootFep = NULL;
       
    75         }
       
    76     // Discard events
       
    77     iMetaDataEvents.Close();
       
    78     iMetaDataSlots.Close();
       
    79     if (iMetaDataStore) 
       
    80         {
       
    81         delete iMetaDataStore;
       
    82         }
       
    83     }
       
    84     
       
    85     
       
    86 // ----------------------------------------------------------------------------
       
    87 // CRsfwFileTable::AddL
       
    88 // this function associates aFep with this file table but does no
       
    89 // yet set to any other node's child (or root node), that must be done sepately
       
    90 // ----------------------------------------------------------------------------
       
    91 //   
       
    92 void CRsfwFileTable::AddL(CRsfwFileEntry* aFep)
       
    93     {    
       
    94     // Just assign a unique id
       
    95     TFid newFid;
       
    96     newFid.iVolumeId = iVolume->iMountInfo.iMountStatus.iVolumeId;
       
    97     newFid.iNodeId = iNodeId;
       
    98     aFep->SetFid(newFid);
       
    99     aFep->iFileTable = this;
       
   100     iNodeId++;
       
   101     if (!iRootFep)
       
   102         {
       
   103         iRootFep = aFep;
       
   104         }
       
   105     // add item to metadata LRU list, 
       
   106     // only add childless directories and non-cached files
       
   107     if ( (aFep->Type() == KNodeTypeFile && aFep->iCachedSize == 0) 
       
   108          || (aFep->Type() == KNodeTypeDir && aFep->Kids()->Count() == 0)
       
   109          || (aFep->Type() == KNodeTypeUnknown) )
       
   110         {
       
   111         iVolume->iVolumeTable->AddToMetadataLRUPriorityListL(aFep, ECachePriorityNormal);        
       
   112         }
       
   113     // Note that the first added entry will always be the root
       
   114     HandleMetaDataEvent(KNotifyNodeAdded, aFep);
       
   115     }
       
   116     
       
   117 // ----------------------------------------------------------------------------
       
   118 // CRsfwFileTable::Remove
       
   119 // removed this fileentry and disconnects from the parent
       
   120 // does not delete the kid file/directory entries
       
   121 // in practise this means that if deleting a directory, all its entries must be deleted
       
   122 // recursively first
       
   123 // ----------------------------------------------------------------------------
       
   124 //   
       
   125 void CRsfwFileTable::RemoveL(CRsfwFileEntry* aFep)
       
   126     {
       
   127     DEBUGSTRING(("CRsfwFileTable::RemoveL"));
       
   128     // remove item from metadata LRU list
       
   129     iVolume->iVolumeTable->RemoveFromMetadataLRUPriorityList(aFep);        
       
   130 
       
   131     if (aFep == iCurrentParent)
       
   132         {
       
   133         iCurrentParent = NULL;
       
   134         }
       
   135     if (iPermanence)
       
   136         {
       
   137         aFep->RemoveCacheFile();
       
   138         HandleMetaDataEvent(KNotifyNodeRemoved, aFep);
       
   139         }
       
   140         
       
   141     // remove this file entry from its parent node    
       
   142     if (aFep->iParent)  
       
   143         {
       
   144         aFep->iParent->RemoveKidL(aFep);
       
   145         }
       
   146     }
       
   147     
       
   148 // ----------------------------------------------------------------------------
       
   149 // CRsfwFileTable::Lookup
       
   150 // ----------------------------------------------------------------------------
       
   151 //   
       
   152 CRsfwFileEntry* CRsfwFileTable::Lookup(const TFid& aFid)
       
   153     {
       
   154     if (!iRootFep)
       
   155         {
       
   156         return NULL;
       
   157         }
       
   158     if (iRootFep->Fid().iNodeId == aFid.iNodeId)
       
   159         {
       
   160         return iRootFep;
       
   161         }
       
   162     // Try to optimize by starting from the latest parent
       
   163     CRsfwFileEntry* fep = NULL;
       
   164     if (iCurrentParent)
       
   165         {
       
   166         fep = iCurrentParent->Lookup(aFid);
       
   167         }
       
   168     if (!fep)
       
   169         {
       
   170         fep = iRootFep->Lookup(aFid);
       
   171         }
       
   172     if (fep)
       
   173         {
       
   174         iCurrentParent = fep->Parent();
       
   175         }
       
   176     return fep;
       
   177     }
       
   178 
       
   179 // ----------------------------------------------------------------------------
       
   180 // CRsfwFileTable::DumpL
       
   181 // ----------------------------------------------------------------------------
       
   182 // 
       
   183 #ifdef _DEBUG
       
   184 void CRsfwFileTable::DumpL(TBool aAll)
       
   185     {
       
   186     if (iRootFep)
       
   187         {
       
   188         iRootFep->PrintL(0, ETrue, aAll);
       
   189         }
       
   190     }
       
   191 #else
       
   192 void CRsfwFileTable::DumpL(TBool /* aAll */)
       
   193     {
       
   194     }
       
   195 #endif //DEBUG
       
   196  
       
   197  
       
   198 // ----------------------------------------------------------------------------
       
   199 // CRsfwFileTable::SetPermanenceL
       
   200 // ----------------------------------------------------------------------------
       
   201 // 
       
   202 void CRsfwFileTable::SetPermanenceL(TBool aPermanence)
       
   203     {
       
   204     if (iPermanence != aPermanence)
       
   205         {
       
   206         iPermanence = aPermanence;
       
   207         if (!iPermanence)
       
   208             {
       
   209             delete iMetaDataStore;
       
   210             iMetaDataStore = NULL;
       
   211             }
       
   212         SetupCacheL();
       
   213         }
       
   214     }
       
   215        
       
   216 // ----------------------------------------------------------------------------
       
   217 // CRsfwFileTable::HandleMetaDataEvent
       
   218 // ----------------------------------------------------------------------------
       
   219 // 
       
   220 void CRsfwFileTable::HandleMetaDataEvent(TInt aEvent, CRsfwFileEntry* aFep)
       
   221     {
       
   222     if (iMetaDataSaveState == EMetaDataSaveFailed)
       
   223         {
       
   224         // No use
       
   225         return;
       
   226         }
       
   227 
       
   228     switch (aEvent)
       
   229         {
       
   230 
       
   231     case KNotifyNodeAdded:
       
   232         {
       
   233         // There should not be any previous additions
       
   234         AddEvent(aEvent, aFep);
       
   235         }
       
   236         break;
       
   237 
       
   238     case KNotifyNodeModified:
       
   239         {
       
   240         // There may appear spurious modifications
       
   241         // to removed entries (like cache state set to false).
       
   242         // We filter them out.
       
   243         if (!NodeEvent(aFep->Fid().iNodeId))
       
   244             {
       
   245             AddEvent(aEvent, aFep);
       
   246             }
       
   247         }
       
   248         break;
       
   249 
       
   250     case KNotifyNodeRemoved:
       
   251         {
       
   252         TMetaDataEvent* oldEvent = NodeEvent(aFep->Fid().iNodeId);
       
   253         if (oldEvent)
       
   254             {
       
   255             if (oldEvent->iEvent == KNotifyNodeAdded)
       
   256                 {
       
   257                 // just remove a previous "added"
       
   258                 RemoveEvent(oldEvent->iNodeId);
       
   259                 AddEvent(aEvent, aFep);
       
   260                 }
       
   261             else
       
   262                 {
       
   263                 // Just replace "modified" (or duplicate "deleted")
       
   264                 // with "deleted"
       
   265                 oldEvent->iEvent = KNotifyNodeRemoved;
       
   266                 }
       
   267             }
       
   268         else
       
   269             {
       
   270             AddEvent(aEvent, aFep);
       
   271             }
       
   272         }
       
   273         break;
       
   274         
       
   275     default:
       
   276         break;
       
   277         }
       
   278     }
       
   279 
       
   280 // ----------------------------------------------------------------------------
       
   281 // CRsfwFileTable::LoadMetaDataL
       
   282 // ----------------------------------------------------------------------------
       
   283 // 
       
   284 CRsfwFileEntry* CRsfwFileTable::LoadMetaDataL()
       
   285     {
       
   286     // When this function is called the root node
       
   287     // must already be created in the file table
       
   288     iMetaDataStore->CompactL();
       
   289     iMetaDataStore->ResetL(EFalse);
       
   290 
       
   291     RPointerArray<CRsfwFileEntry> feps;
       
   292     CleanupClosePushL(feps);
       
   293 
       
   294     TBool done = EFalse;
       
   295     while (!done)
       
   296         {
       
   297         CRsfwFileEntry* fep;
       
   298         TMetaDataSlot slot;
       
   299         TRAPD(err, LoadNodeL(fep, slot.iSlotId));
       
   300         if (err == KErrNone)
       
   301             {
       
   302             if (fep != NULL) 
       
   303                 {
       
   304                 feps.Append(fep);
       
   305                 slot.iNodeId = fep->Fid().iNodeId;
       
   306                 iMetaDataSlots.Append(slot);
       
   307                 if (!fep->iParentNodeId)
       
   308                     {
       
   309                     // This must be the root
       
   310                     DEBUGSTRING(("Root found at slot %d",
       
   311                              iMetaDataSlots.Count() - 1));
       
   312                     iRootFep = fep;
       
   313                     }
       
   314                 }
       
   315             }
       
   316         else
       
   317             {
       
   318             // All or nothing ...
       
   319             DEBUGSTRING(("LoadNode returned with err = %d", err));
       
   320             if (err != KErrEof)
       
   321                 {
       
   322                 User::Leave(err);
       
   323                 }
       
   324             done = ETrue;
       
   325             }
       
   326         }
       
   327 
       
   328     // Now we have the restored the file entries
       
   329     TInt i;
       
   330     for (i = 0; i < feps.Count(); i++)
       
   331         {
       
   332         CRsfwFileEntry* fep = feps[i];
       
   333         // Determine the next free node id
       
   334         if (fep->Fid().iNodeId >= iNodeId)
       
   335             {
       
   336             iNodeId = fep->Fid().iNodeId + 1;
       
   337             }
       
   338 
       
   339         if (fep->iParentNodeId == 0)
       
   340             {
       
   341             // This is the root node
       
   342             fep->SetParent(NULL);
       
   343             }
       
   344         else if (fep->iParentNodeId == 1)
       
   345             {
       
   346             // The parent is the root node
       
   347             fep->SetParent(iRootFep);
       
   348             iRootFep->iKids.Append(fep);
       
   349             }
       
   350         else
       
   351             {
       
   352             TInt j;
       
   353             // This is O(n**2)
       
   354             for (j = 0; j < feps.Count(); j++)
       
   355                 {
       
   356                 if (j != i)
       
   357                     {
       
   358                     // Find the parent for the node
       
   359                     CRsfwFileEntry* parent = feps[j];
       
   360                     if (fep->iParentNodeId == parent->Fid().iNodeId)
       
   361                         {
       
   362                         // Set up the two-way linkage
       
   363                         fep->SetParent(parent);
       
   364                         parent->iKids.Append(fep);
       
   365                         break;
       
   366                         }
       
   367                     }
       
   368                 }
       
   369             }
       
   370         }
       
   371 
       
   372     // Final fixes
       
   373     for (i = 0; i < feps.Count(); i++)
       
   374         {
       
   375         CRsfwFileEntry* fep = feps[i];
       
   376         // Fix volume ids and such ...
       
   377         TFid fid;
       
   378         fid = fep->Fid();
       
   379         fid.iVolumeId = iVolume->iMountInfo.iMountStatus.iVolumeId;
       
   380         fep->SetFid(fid);
       
   381         fep->iFileTable = this;
       
   382         // Add to LRU list (only cached files)
       
   383         if ( fep->Type() == KNodeTypeFile && fep->IsCached() 
       
   384             && (!iVolume->iVolumeTable->iUseExternalizedLRUList))
       
   385             {
       
   386             iVolume->iVolumeTable->AddToLRUPriorityListL(fep, ECachePriorityNormal);
       
   387             }
       
   388         // add item to metadata LRU list, 
       
   389         // only add childless directories and non-cached files
       
   390         if ( (fep->Type() == KNodeTypeFile && fep->iCachedSize == 0) 
       
   391              || (fep->Type() == KNodeTypeDir && fep->Kids()->Count() == 0) )
       
   392             {
       
   393             iVolume->iVolumeTable->AddToMetadataLRUPriorityListL(fep, ECachePriorityNormal);        
       
   394             }
       
   395   
       
   396         // Check consistency
       
   397         if ((fep != iRootFep) && (!fep->Parent()))
       
   398             {
       
   399             // Should never happen
       
   400             DEBUGSTRING16(("LodaMetaDataL() - parent missing for '%S'",
       
   401                            fep->Name()));
       
   402             }
       
   403         }
       
   404         
       
   405     // Now we don't need the file entry pointer array any more
       
   406     CleanupStack::PopAndDestroy(&feps); // feps
       
   407     return iRootFep;
       
   408     }
       
   409         
       
   410 // ----------------------------------------------------------------------------
       
   411 // CRsfwFileTable::SaveMetaDataDelta
       
   412 // ----------------------------------------------------------------------------
       
   413 // 
       
   414 TInt CRsfwFileTable::SaveMetaDataDelta()
       
   415     {
       
   416     DEBUGSTRING16(("CRsfwFileTable::SaveMetaDataDelta"));
       
   417     TRAPD(err, SaveMetaDataDeltaL());
       
   418     if (err != KErrNone)
       
   419         {
       
   420         DEBUGSTRING(("SaveMetaDataDeltaL() returns %d", err));
       
   421         // Stop recording meta data
       
   422         iMetaDataEvents.Reset();
       
   423         iMetaDataSaveState = EMetaDataSaveFailed;
       
   424         }
       
   425     return err;
       
   426     }
       
   427 
       
   428 // ----------------------------------------------------------------------------
       
   429 // CRsfwFileTable::SetupCacheL
       
   430 // ----------------------------------------------------------------------------
       
   431 // 
       
   432 void CRsfwFileTable::SetupCacheL()
       
   433     {
       
   434     if (iPermanence)
       
   435         {
       
   436         iMetaDataStore = CRsfwMetaDataStore::NewL(iMetaDataFilePath); 
       
   437         DEBUGSTRING(("SetupCacheL()"));
       
   438         // The format of label is <drive_letter>:<uri>.
       
   439         TRsfwMountConfig mountConfig;
       
   440         TRAPD(err, iMetaDataStore->GetMountConfigL(mountConfig));
       
   441         if ((err != KErrNone) ||
       
   442             mountConfig.iUri.Compare(iVolume->iMountInfo.iMountConfig.iUri) !=
       
   443             0)
       
   444             {
       
   445             // The saved metadata is not current - delete all
       
   446             DEBUGSTRING(("Clearing Metadata ..."));
       
   447             delete iMetaDataStore;
       
   448             iMetaDataStore = NULL;
       
   449             ClearCacheL();
       
   450             // Start from scratch
       
   451             iMetaDataStore = CRsfwMetaDataStore::NewL(iMetaDataFilePath);
       
   452             iMetaDataStore->SetMountConfigL(iVolume->iMountInfo.iMountConfig);
       
   453             }
       
   454         }
       
   455     else
       
   456         {
       
   457         ClearCacheL();
       
   458         }
       
   459     }
       
   460 
       
   461 // ----------------------------------------------------------------------------
       
   462 // CRsfwFileTable::TotalCachedSize
       
   463 // ----------------------------------------------------------------------------
       
   464 // 
       
   465 TInt CRsfwFileTable::TotalCachedSize() 
       
   466     {
       
   467     if (!iRootFep)
       
   468         {
       
   469         return 0;
       
   470         }
       
   471     return iRootFep->TotalCachedSize(); 
       
   472     }
       
   473 
       
   474 // ----------------------------------------------------------------------------
       
   475 // CRsfwFileTable::TotalEntryCount
       
   476 // ----------------------------------------------------------------------------
       
   477 // 
       
   478 TInt CRsfwFileTable::TotalEntryCount() 
       
   479     {
       
   480     if (!iRootFep)
       
   481         {
       
   482         return 0;
       
   483         }
       
   484     return iRootFep->TotalEntryCount(); 
       
   485     }
       
   486 
       
   487 // ----------------------------------------------------------------------------
       
   488 // CRsfwFileTable::ClearCacheL
       
   489 // ----------------------------------------------------------------------------
       
   490 // 
       
   491 void CRsfwFileTable::ClearCacheL()
       
   492     {
       
   493     DEBUGSTRING(("Clearing cache ..."));
       
   494     TFileName cachePath = iCachePath;
       
   495     _LIT(KWild, "*");
       
   496     cachePath.Append(KWild);
       
   497     
       
   498     CFileMan* fM = CFileMan::NewL(iFs);
       
   499     CleanupStack::PushL(fM);
       
   500     TInt err = fM->Delete(cachePath, CFileMan::ERecurse);
       
   501     CleanupStack::PopAndDestroy(fM); // fM
       
   502     if (err != KErrNone)
       
   503         {
       
   504         DEBUGSTRING16(("Cache cleaning of '%S' failed with err=%d",
       
   505                        &cachePath,
       
   506                        err));
       
   507         }
       
   508     }
       
   509 
       
   510 // ----------------------------------------------------------------------------
       
   511 // CRsfwFileTable::NodeEvent
       
   512 // ----------------------------------------------------------------------------
       
   513 //   
       
   514 TMetaDataEvent* CRsfwFileTable::NodeEvent(TInt aNodeId)
       
   515     {
       
   516     // Search downwards (for efficiency)
       
   517     TInt count = iMetaDataEvents.Count();
       
   518     if (count)
       
   519         {
       
   520         TInt i;
       
   521         for (i = count - 1; i >= 0; i--)
       
   522             {
       
   523             if (iMetaDataEvents[i].iNodeId == aNodeId)
       
   524                 {
       
   525                 return &iMetaDataEvents[i];
       
   526                 }
       
   527             }
       
   528         }
       
   529     return NULL;
       
   530     }
       
   531     
       
   532 // ----------------------------------------------------------------------------
       
   533 // CRsfwFileTable::AddEvent
       
   534 // ----------------------------------------------------------------------------
       
   535 //   
       
   536 void CRsfwFileTable::AddEvent(TInt aEvent, CRsfwFileEntry* aFep)
       
   537     {
       
   538     TMetaDataEvent event;
       
   539     event.iEvent = aEvent;
       
   540     event.iEntry = aFep;
       
   541     event.iNodeId= aFep->Fid().iNodeId;
       
   542     // For searching efficiency insert at the head
       
   543     if (iMetaDataEvents.Append(event) != KErrNone)
       
   544         {
       
   545         iMetaDataEvents.Close();
       
   546         iMetaDataSaveState = EMetaDataSaveFailed;
       
   547         }
       
   548     }
       
   549 
       
   550 // ----------------------------------------------------------------------------
       
   551 // CRsfwFileTable::RemoveEvent
       
   552 // ----------------------------------------------------------------------------
       
   553 //   
       
   554 void CRsfwFileTable::RemoveEvent(TInt aNodeId)
       
   555     {
       
   556     TInt i;
       
   557     for (i = 0; i < iMetaDataEvents.Count(); i++)
       
   558         {
       
   559         if (iMetaDataEvents[i].iNodeId == aNodeId)
       
   560             {
       
   561             iMetaDataEvents.Remove(i);
       
   562             return;
       
   563             }
       
   564         }
       
   565     }
       
   566 
       
   567 // ----------------------------------------------------------------------------
       
   568 // CRsfwFileTable::LoadNodeL
       
   569 // ----------------------------------------------------------------------------
       
   570 // 
       
   571 void CRsfwFileTable::LoadNodeL(CRsfwFileEntry*& aFep, TInt &aSlot)
       
   572     {
       
   573     // Internalize a file entry
       
   574     // Read data from the file at the specified slot
       
   575     HBufC8* buf = HBufC8::NewLC(KMaxExternalizedFileEntrySize);
       
   576     TPtr8 ptr = buf->Des();
       
   577     TUint8* data = const_cast<TUint8 *>(ptr.Ptr());
       
   578     TInt dataLength;
       
   579     iMetaDataStore->GetNextDataL(data, dataLength, aSlot);
       
   580     RMemReadStream stream(data, dataLength);
       
   581     CleanupClosePushL(stream);
       
   582     CRsfwFileEntry* fep = CRsfwFileEntry::NewL(stream);
       
   583     DEBUGSTRING16(("CRsfwFileTable::LoadNodeL: Loaded node '%S'(id=%d, pid=%d, cn='%S')",
       
   584                    fep->Name(),
       
   585                    fep->Fid().iNodeId,
       
   586                    fep->iParentNodeId,
       
   587                    &fep->iCacheName));
       
   588     CleanupStack::PopAndDestroy(2); // stream, buf
       
   589 
       
   590     aFep = fep;
       
   591     }
       
   592     
       
   593 // ----------------------------------------------------------------------------
       
   594 // CRsfwFileTable::SaveNodeL
       
   595 // ----------------------------------------------------------------------------
       
   596 // 
       
   597 void CRsfwFileTable::SaveNodeL(CRsfwFileEntry* aFep, TInt& aSlot)
       
   598     {
       
   599     // Externalize the file entry
       
   600     HBufC8* buf = HBufC8::NewLC(KMaxExternalizedFileEntrySize);
       
   601     TPtr8 ptr = buf->Des();
       
   602     TUint8* data = const_cast<TUint8 *>(ptr.Ptr());
       
   603     TInt dataLen;
       
   604 
       
   605     RMemWriteStream stream(data, KMaxExternalizedFileEntrySize);
       
   606     CleanupClosePushL(stream);
       
   607 
       
   608     if (aFep)
       
   609         {
       
   610         // dump the externalized data in the memory buffer
       
   611         // stream << *aFep;
       
   612         aFep->ExternalizeL(stream);
       
   613         MStreamBuf* streamBuf = stream.Sink();
       
   614         dataLen = streamBuf->TellL(MStreamBuf::EWrite).Offset();
       
   615         stream.CommitL();
       
   616         }
       
   617     else
       
   618         {
       
   619 
       
   620         DEBUGSTRING(("Removing slot %d", aSlot));
       
   621         // This will clear the slot
       
   622         data = NULL;
       
   623         dataLen = 0;
       
   624         }
       
   625 
       
   626     // Write data to the file at the specified slot
       
   627     iMetaDataStore->PutDataL(data, dataLen, aSlot);
       
   628 
       
   629     CleanupStack::PopAndDestroy(2, buf); // stream, buf
       
   630     }
       
   631     
       
   632 // ----------------------------------------------------------------------------
       
   633 // CRsfwFileTable::SaveMetaDataDeltaL
       
   634 // ----------------------------------------------------------------------------
       
   635 // 
       
   636 void CRsfwFileTable::SaveMetaDataDeltaL()
       
   637     {
       
   638     DEBUGSTRING(("CRsfwFileTable::SaveMetaDataDeltaL"));
       
   639     if (!iPermanence)
       
   640         {
       
   641         return;
       
   642         }
       
   643 
       
   644     if (iMetaDataEvents.Count() == 0)
       
   645 
       
   646         {
       
   647         // Nothing to do
       
   648         return;
       
   649         }
       
   650 
       
   651     switch (iMetaDataSaveState)
       
   652         {
       
   653     case EMetaDataSaveNone:
       
   654         iMetaDataStore->ResetL(ETrue);
       
   655         iMetaDataSaveState = EMetaDataSaveStarted;
       
   656         break;
       
   657 
       
   658     case EMetaDataSaveStarted:
       
   659         break;
       
   660 
       
   661     case EMetaDataSaveFailed:
       
   662         DEBUGSTRING(("EMetaDataSaveFailed!"));
       
   663         User::Leave(KErrGeneral);
       
   664         break;
       
   665 
       
   666     default:
       
   667         break;
       
   668         }
       
   669 
       
   670     TInt i;
       
   671     for (i = 0; i < iMetaDataEvents.Count(); i++)
       
   672         {
       
   673         TInt slotPos;
       
   674         TMetaDataEvent *event = &iMetaDataEvents[i];
       
   675         
       
   676         DEBUGSTRING(("SaveMetaDataDeltaL: id=%d, event=%d",
       
   677                      event->iNodeId,
       
   678                      event->iEvent));
       
   679 
       
   680         switch (event->iEvent)
       
   681             {
       
   682         case KNotifyNodeModified:
       
   683         case KNotifyNodeAdded:
       
   684             {
       
   685             TMetaDataSlot s; // dummy for finding
       
   686             s.iNodeId = event->iNodeId;
       
   687             slotPos = iMetaDataSlots.Find(s);
       
   688             TInt slotId;
       
   689             if (slotPos != KErrNotFound)
       
   690                 {
       
   691                 slotId = iMetaDataSlots[slotPos].iSlotId;
       
   692                 }
       
   693             else
       
   694                 {
       
   695                 // We don't have a slot yet
       
   696                 slotId = -1;
       
   697                 }
       
   698             SaveNodeL(event->iEntry, slotId);
       
   699             if (slotPos == KErrNotFound)
       
   700                 {
       
   701                 TMetaDataSlot slot;
       
   702                 slot.iNodeId = event->iEntry->Fid().iNodeId;
       
   703                 slot.iSlotId = slotId;
       
   704                 iMetaDataSlots.Append(slot);
       
   705                 }
       
   706             else
       
   707                 {
       
   708                 // The index may have changed
       
   709                 iMetaDataSlots[slotPos].iSlotId = slotId;
       
   710                 }
       
   711             }
       
   712             break;
       
   713             
       
   714         case KNotifyNodeRemoved:
       
   715             {
       
   716             TMetaDataSlot s; // dummy for finding
       
   717             s.iNodeId = event->iNodeId;
       
   718             slotPos = iMetaDataSlots.Find(s);
       
   719             if (slotPos != KErrNotFound)
       
   720                 {
       
   721                 TInt slotId = iMetaDataSlots[slotPos].iSlotId;
       
   722                 iMetaDataSlots.Remove(slotPos);
       
   723                 // Saving null is the same as removing
       
   724                 SaveNodeL(NULL, slotId);              
       
   725                 }
       
   726             }
       
   727             break;
       
   728             
       
   729         default:
       
   730             break;
       
   731             }
       
   732         }
       
   733     iMetaDataEvents.Reset();
       
   734 
       
   735     User::LeaveIfError(iMetaDataStore->Commit());
       
   736 #if 0
       
   737     iMetaDataStore->CompactL();
       
   738 #endif
       
   739     }
       
   740 
       
   741 
       
   742 void CRsfwFileTable::ResolveDirtyFilesL() 
       
   743     {
       
   744     DEBUGSTRING(("CRsfwFileTable::ResolveDirtyFilesL"));
       
   745     if (iRootFep)
       
   746         {
       
   747         iRootFep->ResolveDirtyFilesL(); 
       
   748         }   
       
   749     SaveMetaDataDeltaL();    
       
   750     }
       
   751 
       
   752 void CRsfwFileTable::ResolveDirtyFileL(CRsfwFileEntry *aFileEntry)
       
   753     {
       
   754     DEBUGSTRING(("CRsfwFileTable::ResolveDirtyFileL"));
       
   755 	if ((aFileEntry->IsOpenedForWriting() && (aFileEntry->CacheFileName())))
       
   756 		{
       
   757 		
       
   758 		DEBUGSTRING16(("file %S has uncommitted modifications, must be saved locally", aFileEntry->Name()));
       
   759 		// file with uncommitted modifications
       
   760 		// (i.e. saving changes to a remote server failed
       
   761 		// show "save as" dialog for this file
       
   762 		TRequestStatus status;
       
   763 		TInt err;
       
   764     	TPckgBuf<TRsfwSaveToDlgRequest>   savetoRequest;
       
   765 		TBuf<KRsfwMaxFileSizeString> fileSizeString;
       
   766         TEntry fEntry;
       
   767         CRsfwRfeServer::Env()->iFs.Entry((*(aFileEntry->CacheFileName())), fEntry);
       
   768         fileSizeString.Num(fEntry.iSize);
       
   769 		TPtrC cacheDriveLetter = aFileEntry->CacheFileName()->Left(1);
       
   770 	
       
   771 	    savetoRequest().iMethod = TRsfwNotPluginRequest::ESaveToDlg;
       
   772         savetoRequest().iDriveName = Volume()->MountInfo()->iMountConfig.iName;								
       
   773         savetoRequest().iFileName = *(aFileEntry->Name());
       
   774         savetoRequest().iCacheDrive = cacheDriveLetter;
       
   775         savetoRequest().iFileSize = fileSizeString;
       
   776 
       
   777 		
       
   778 		RNotifier notifier;
       
   779 		User::LeaveIfError(notifier.Connect());
       
   780 		notifier.StartNotifierAndGetResponse(status, KRsfwNotifierPluginUID,
       
   781                     savetoRequest, savetoRequest);
       
   782         User::WaitForRequest(status);
       
   783 		notifier.NotifyCancel();
       
   784 		notifier.Close();
       
   785 	
       
   786         if (status.Int() != KErrCancel) 
       
   787             {
       
   788             // move the file from cache to the new location
       
   789 		    HBufC* newName = HBufC::NewMaxLC(KMaxPath);
       
   790             TPtr pathPtr = newName->Des();
       
   791             pathPtr = savetoRequest().iFileName;
       
   792             CFileMan* fman = CFileMan::NewL(CRsfwRfeServer::Env()->iFs);
       
   793             // we assume that this is local-to-local move, and can be synch. call
       
   794             err = fman->Move(*(aFileEntry->CacheFileName()), pathPtr, CFileMan::EOverWrite);
       
   795             delete fman;
       
   796             if (err == KErrNone) 
       
   797                 {
       
   798                 Volume()->iVolumeTable->WaitNoteManager()->ShowFileSavedToDialogL(pathPtr);
       
   799                 }
       
   800             else 
       
   801                 {
       
   802                 Volume()->iVolumeTable->WaitNoteManager()->ShowFailedSaveNoteL();
       
   803                 }
       
   804    
       
   805             CleanupStack::PopAndDestroy(newName);
       
   806             }
       
   807         
       
   808         // in any case, remove the file entry from the file table and cache
       
   809         // (has been moved or deleted)
       
   810         RemoveL(aFileEntry);
       
   811         delete aFileEntry;
       
   812         aFileEntry = NULL;
       
   813         DEBUGSTRING(("possible uncommitted modifications resolved"));  
       
   814 		}
       
   815     }
       
   816