remotestoragefw/remotefileengine/src/rsfwfileentry.cpp
branchRCL_3
changeset 20 1aa8c82cb4cb
parent 0 3ad9d5175a89
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/remotestoragefw/remotefileengine/src/rsfwfileentry.cpp	Wed Sep 01 12:15:08 2010 +0100
@@ -0,0 +1,1356 @@
+/*
+* Copyright (c) 2003-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:  metadata struct for a remote file entry
+*
+*/
+
+
+#include <bautils.h>
+
+#include "rsfwfileentry.h"
+#include "rsfwfiletable.h"
+#include "rsfwconfig.h"
+#include "rsfwvolumetable.h"
+#include "rsfwvolume.h"
+#include "rsfwrfeserver.h"
+#include "rsfwlockmanager.h"
+#include "mdebug.h"
+#include "rsfwdirentattr.h"
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::NewLC
+// ----------------------------------------------------------------------------
+//
+CRsfwFileEntry* CRsfwFileEntry::NewLC(const TDesC& aName, CRsfwFileEntry* aParent)
+    {
+    CRsfwFileEntry* self = new (ELeave) CRsfwFileEntry();
+    CleanupStack::PushL(self);
+    self->ConstructL(aName, aParent);
+    return self;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::NewL
+// ----------------------------------------------------------------------------
+//
+CRsfwFileEntry* CRsfwFileEntry::NewL(const TDesC& aName, CRsfwFileEntry* aParent)
+    {
+    CRsfwFileEntry* self = NewLC(aName, aParent);
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::NewL
+// ----------------------------------------------------------------------------
+//
+CRsfwFileEntry* CRsfwFileEntry::NewL(RReadStream& aStream)
+    {
+    CRsfwFileEntry* self = new (ELeave) CRsfwFileEntry();
+    CleanupStack::PushL(self);
+    self->ConstructL(aStream);
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::ConstructL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::ConstructL(const TDesC& aName, CRsfwFileEntry* aParent)
+    {
+    iType = KNodeTypeUnknown;
+    iParent = aParent;
+    iName = aName.AllocL();
+    iAtt = KEntryAttRemote;
+    iCachePriority = ECachePriorityNormal;
+    
+    SetLockTimeout();
+    // Note that we don't yet attach the kid to its parent
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::ConstructL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::ConstructL(RReadStream& aStream)
+    {
+    // aStream >> *this;
+    this->InternalizeL(aStream);
+    SetLockTimeout();
+    // Note that we don't yet attach the kid to its parent
+    }
+
+void CRsfwFileEntry::SetLockTimeout() 
+    {
+    // When creating a file entry, the lock timeout is set to default
+    // even when internalizing from stream.
+    // We do not assume any locks that would survive server restarts
+    TInt timeout;
+    TInt err = CRsfwRfeServer::Env()->iRsfwConfig->Get(RsfwConfigKeys::KLockTimeout,
+                                                       timeout);
+    if (!err)
+        {
+        iLockTimeout = (TUint)timeout;
+        }
+    else
+        {
+        iLockTimeout = KDefaultLockTimeout;
+        }
+    
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::~CRsfwFileEntry
+// ----------------------------------------------------------------------------
+//
+CRsfwFileEntry::~CRsfwFileEntry()
+    {
+    if (iFlags & KNodeHasValidLock)
+        {
+        if (iLockManager)
+            {
+            iLockManager->RemoveLockedEntry(this);
+            }
+        }
+    delete iName;
+    delete iMimeType;
+    delete iOpaqueFileId;
+    delete iLockToken;
+    
+    if (!iFileTable || !iFileTable->Permanence())
+        {
+        RemoveCacheFile();
+        }
+    
+    if ( iFileTable )
+        {
+        iFileTable->Volume()->iVolumeTable->RemoveFromMetadataLRUPriorityList(this);        
+        }
+    
+    delete iLockTimer;
+
+    // delete kids
+    TInt i;
+    for(i = 0; i < iKids.Count(); i++)
+        {
+        delete iKids[i];
+        }
+    iKids.Close();
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::FindKidByName
+// ----------------------------------------------------------------------------
+//
+CRsfwFileEntry* CRsfwFileEntry::FindKidByName(const TDesC& aName)
+    {
+     DEBUGSTRING(("CRsfwFileEntry::FindKidByName"));
+    // finds a kid from a parent directory
+    TInt i;
+    for (i = 0; i < iKids.Count(); i++)
+        {
+        CRsfwFileEntry* kid = iKids[i];
+        if (kid->iName->Compare(aName) == 0)
+            {
+            return iKids[i];
+            }
+        }
+    DEBUGSTRING(("...kid not found!"));   
+    return NULL;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::RenameL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::RenameL(const TDesC& aName)
+    {
+    delete iName;
+    iName = NULL;
+    iName = aName.AllocL();
+    ReportEvent(KNotifyNodeModified);
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::AddKid
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::AddKid(CRsfwFileEntry& aFe)
+    {
+    // if this is the first kid to be added then probably
+    // we have to remove the entry from metadata LRU list
+    if ( iKids.Count() == 0 )
+        {
+        iFileTable->Volume()->iVolumeTable->RemoveFromMetadataLRUPriorityList(this);
+        }
+    iKids.Append(&aFe);
+    // (This assignment is sometimes redundant)
+    aFe.SetParent(this);
+    ReportEvent(KNotifyNodeModified);
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::RemoveKidL
+// ----------------------------------------------------------------------------
+//
+TInt CRsfwFileEntry::RemoveKidL(CRsfwFileEntry* aFep)
+    {
+    TInt i;
+    for (i = 0; i < iKids.Count(); i++)
+        {
+        if (iKids[i] == aFep)
+            {
+            ReportEvent(KNotifyNodeModified);
+            iKids.Remove(i);
+            // if we've just removed the last kid of the entry
+            // we can add the entry to metadata LRU list
+            if ( iKids.Count() == 0 )
+                {
+                iFileTable->Volume()->iVolumeTable->AddToMetadataLRUPriorityListL(this, ECachePriorityNormal);
+                }
+            return KErrNone;
+            }
+        }
+    DEBUGSTRING(("remove kid %d not found in %d",
+                 aFep->Fid().iNodeId,
+                 Fid().iNodeId));
+    return KErrNotFound;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::KidsCount
+// ----------------------------------------------------------------------------
+//
+TInt CRsfwFileEntry::KidsCount()
+    {
+    return iKids.Count();
+    }
+
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::UnmarkKids
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::UnmarkKids()
+    {
+    TInt i;
+    for (i = 0; i < iKids.Count(); i++)
+        {
+        iKids[i]->Unmark();
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::DropUnmarkedKidsL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::DropUnmarkedKidsL()
+    {
+    TInt i = 0;
+    while (i < iKids.Count())
+        {
+        if (!iKids[i]->IsMarked())
+            {
+            iKids[i]->DropLD();
+            }
+        else
+            {
+            i++;
+            }
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::DropLD
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::DropLD()
+    {
+    DEBUGSTRING(("CRsfwFileEntry::DropLD"));
+    TInt i = 0;
+    while (i < iKids.Count())
+        {
+        iKids[i]->DropLD();
+        }
+        
+    iFileTable->RemoveL(this);
+    delete this;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::GetAttributes
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::GetAttributes(TDirEntAttr& aAttr) const
+    {
+    aAttr.iAtt = Att();
+    aAttr.iSize = Size();
+    aAttr.iModified = Modified();
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::GetAttributesL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::GetAttributesL(CRsfwDirEntAttr& aAttr) const
+    {
+    aAttr.SetAtt(Att());
+    aAttr.SetSize(Size());
+    aAttr.SetModified(Modified());
+    if (iOpaqueFileId)
+        {
+        aAttr.SetETagL(*OpaqueFileId());
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::SetAttributesL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::SetAttributesL(CRsfwDirEntAttr& aAttr,
+                                    TBool aAllMetaData)
+    {
+    SetAtt(aAttr.Att());
+    if (aAllMetaData) 
+        {
+        SetSize(aAttr.Size());
+        SetModified(aAttr.Modified());
+        if (aAttr.MimeType())
+            {
+            SetMimeTypeL(*aAttr.MimeType());
+            }
+        if (aAttr.ETag())
+            {
+            SetOpaqueFileIdL(*aAttr.ETag());
+            }
+        SetUid(aAttr.Uid());
+        SetAttribValidationTime();
+        }
+
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::CacheFileName
+// ----------------------------------------------------------------------------
+//
+TDesC* CRsfwFileEntry::CacheFileName()
+    {
+    DEBUGSTRING(("CRsfwFileEntry::CacheFileName"));
+    if (iCacheName.Length())
+        {
+        return &iCacheName;
+        }
+    return NULL;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::SetCacheFileName
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::SetCacheFileName(TDesC* aFn)
+    {
+    DEBUGSTRING16(("SetCacheFileName for file %S", Name()));
+    if (aFn)
+        {
+        iCacheName = *aFn;
+        ReportEvent(KNotifyNodeModified);
+        }
+    else
+        {
+        if (iCacheName.Length())
+            {
+            if (IsCached())
+                {
+                // Remove the cache list entry...
+                iFileTable->
+                    Volume()->
+                    iVolumeTable->RemoveFromLRUPriorityList(this);
+                }
+            // This is a request to discard the container
+            RFs fs = CRsfwRfeServer::Env()->iFs;
+            TInt err = fs.Delete(iCacheName);
+            if (err != KErrNone)
+                {
+                DEBUGSTRING(("Cannot purge cache file (err=%d)", err));
+                }
+            iCacheName.Zero();
+            // Reset locally dirty in case this is a directory.
+            // "locally dirty" means that the container
+            // doesn't have the "cached"/"protected" indicator bits up to date
+            // (these indicators refer to files contained in the directory).
+            iFlags &= ~KNodeLocallyDirty;
+            ReportEvent(KNotifyNodeModified);
+            }
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::IsCached
+// ----------------------------------------------------------------------------
+//
+TBool CRsfwFileEntry::IsCached() const
+    {
+   DEBUGSTRING(("CRsfwFileEntry::IsCached, iAtt = %d, iFlags = %d", iAtt, iFlags));
+    if (((iAtt & KEntryAttRemote) == 0) ||
+        (iFlags & KNodePartlyCached))
+        {
+         DEBUGSTRING(("returning ETrue"));
+        // File is either fully or partly cached
+        return ETrue;
+        }
+        
+    DEBUGSTRING(("returning EFalse"));
+    return EFalse;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::IsFullyCached
+// ----------------------------------------------------------------------------
+//
+TBool CRsfwFileEntry::IsFullyCached() const
+    {
+    DEBUGSTRING(("CRsfwFileEntry::IsFullyCached"));
+    DEBUGSTRING(("iCachedSize = %d, iSize = %d", iCachedSize, iSize));
+    if (Type() == KNodeTypeDir)
+        {
+        return IsCached();
+        }
+    else
+        {
+        if (iCachedSize == iSize)
+            {
+            return IsCached();
+            }
+        else
+            {
+            return EFalse;
+            }
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::SetCached
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::SetCached(TBool aCached)
+    {
+    DEBUGSTRING(("CRsfwFileEntry::SetCached"));
+    TUint oldAtt = iAtt;
+    if (aCached)
+        {
+        if (Type() == KNodeTypeDir)
+            {
+            // set to fully cached
+            DEBUGSTRING(("set directory to fully cached"));
+            iAtt &= ~KEntryAttRemote;
+            iFlags &= ~KNodePartlyCached;
+            }
+        else
+            {
+            if (iCachedSize == iSize)
+                {
+                // set file to fully cached
+                DEBUGSTRING(("set file to fully cached"));
+                iAtt &= ~KEntryAttRemote;
+                iFlags &= ~KNodePartlyCached;
+                }
+            else
+                {
+                // Set file to partly cached
+                DEBUGSTRING(("set file to partly cached"));
+                iAtt |= KEntryAttRemote;
+                iFlags |= KNodePartlyCached;
+                }
+            }
+        }
+    else
+        {
+        // set to "fully" remote
+        DEBUGSTRING(("set to fully remote"));
+        iFlags &= ~KNodePartlyCached;
+        iAtt |= KEntryAttRemote;
+        iUseCachedData = EFalse;
+        iCachedSize = 0;
+        }
+    if (iAtt != oldAtt)
+        {
+        ReportEvent(KNotifyNodeModified);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::SetCachedSize
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::SetCachedSize(TInt aFetchedSize)
+    {
+    TInt oldCachedSize = iCachedSize;
+    iCachedSize = aFetchedSize;
+    if (iCachedSize != oldCachedSize)
+        {
+        ReportEvent(KNotifyNodeModified);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::RemoveCacheFile
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::RemoveCacheFile()
+    {
+   DEBUGSTRING(("CRsfwFileEntry::RemoveCacheFile"));
+    if (IsCached() && iFileTable)
+        {
+        // Remove the cache list entry...
+        iFileTable->Volume()->iVolumeTable->RemoveFromLRUPriorityList(this);
+        }
+
+    if (iCacheName.Length())
+        {
+        RFs fs = CRsfwRfeServer::Env()->iFs;
+        TInt err = fs.Delete(iCacheName);
+        if ((err != KErrNone) && (err != KErrNotFound))
+            {
+            DEBUGSTRING(("Cannot delete cache file (err=%d)", err));
+            }
+        iCacheName.Zero();
+        }
+    SetCached(EFalse);
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::ValidateCacheFile
+// Function checks whether cache file has not been accidentally or intentionally
+// removed from the cache (which would mean the cache has been corrupted)
+// In case the corruption has happened, the function sets entry as non-cached
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::ValidateCacheFile()
+    {
+    if (iCacheName.Length() > 0)
+        {
+        RFs fs = CRsfwRfeServer::Env()->iFs;
+        if (! BaflUtils::FileExists(fs, iCacheName))
+            {
+            SetCached(EFalse);        
+            }
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::PrintL
+// ----------------------------------------------------------------------------
+//
+#ifdef _DEBUG
+void CRsfwFileEntry::PrintL(TInt aLevel, TBool aKids, TBool aAll) const
+    {
+    if (!IsCached() && !aAll)
+        {
+        // Print only information about cached files
+        return;
+        }
+
+    HBufC* sBuf = HBufC::NewLC(KMaxPath);
+    TPtr s = sBuf->Des();
+
+    s.Fill(' ', 4 * aLevel);
+    s.AppendNum(iFid.iNodeId);
+    s.Append('|');
+    s.Append(*iName);
+    switch (iType)
+        {
+    case KNodeTypeDir:
+        s.Append('/');
+        break;
+
+    case KNodeTypeFile:
+        break;
+
+    default:
+        s.Append('?');
+        break;
+        }
+
+    if (IsCached())
+        {
+        s.Append('|');
+        s.Append(iCacheName);
+        }
+
+    DEBUGBUFFER((s));
+
+    CleanupStack::PopAndDestroy(sBuf); // sBuf
+
+    if (aKids)
+        {
+        TInt i;
+        for (i = 0; i < iKids.Count(); i++)
+            {
+            iKids[i]->PrintL(aLevel + 1, aKids, aAll);
+            }
+        }
+    }
+#else
+void CRsfwFileEntry::PrintL(TInt, TBool, TBool) const
+    {
+    }
+#endif //DEBUG
+
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::FullNameLC
+// Construct full name relative to the root.
+// The caller is responsible for deallocating the return value.
+// ----------------------------------------------------------------------------
+//
+HBufC* CRsfwFileEntry::FullNameLC() const
+    {
+    // We know that we can't have more than KMaxPath entries,
+    // because each entry is minimally "/"
+    CRsfwFileEntry* entList[KMaxPath / 2];
+
+    HBufC* fn = HBufC::NewLC(KMaxPath);
+    TPtr fnp = fn->Des();
+    CRsfwFileEntry* fep = const_cast<CRsfwFileEntry*>(this);
+    TInt depth = 0;
+    do
+        {
+        if (depth >= (KMaxPath / 2))
+            {
+            // Too deep hierarchy
+            DEBUGSTRING(("CRsfwFileEntry::FullNameLC - Too deep hierarchy! %d", depth));
+            User::Leave(KErrGeneral);
+            }
+        entList[depth++] = fep;
+        fep = fep->iParent;
+        }
+    while (fep);
+
+    // We want to avoid going right to the root to avoid dots
+    depth--;
+
+    TInt i;
+    for (i = depth - 1; i >= 0; i--)
+        {
+        TPtr name = entList[i]->iName->Des();
+        if (i != (depth - 1))
+            {
+            // Skip "this" directories (should not happen)
+            if ((name[0] == '.') && (name.Length() == 1))
+                {
+                continue;
+                }
+            }
+        if ((fnp.Length() + name.Length()) >= (KMaxPath - 1))
+            {
+            // Too long name
+            DEBUGSTRING(("CRsfwFileEntry::FullNameLC - Too long name!"));
+            User::Leave(KErrGeneral);
+            }
+        fnp.Append(name);
+        if (i != 0)
+            {
+            fnp.Append('/');
+            }
+        }
+
+    return fn;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::TotalCachedSize
+// ----------------------------------------------------------------------------
+//
+TInt CRsfwFileEntry::TotalCachedSize()
+    {
+    TInt cachedSize = 0;
+    TInt i;
+    
+    for (i = 0; i < iKids.Count(); i++)
+        {
+        TInt newSize = iKids[i]->TotalCachedSize();
+        cachedSize = cachedSize + newSize;
+        }
+    cachedSize = cachedSize + iCachedSize;
+    return cachedSize;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::TotalEntryCount
+// ----------------------------------------------------------------------------
+//
+TInt CRsfwFileEntry::TotalEntryCount()
+    {
+    TInt entryCount = 0;
+    TInt i;
+    for (i = 0; i < iKids.Count(); i++)
+        {
+        TInt kidCount = iKids[i]->TotalEntryCount();
+        entryCount += kidCount;
+        }
+    entryCount += 1; // itself
+    return entryCount;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::Lookup
+// ----------------------------------------------------------------------------
+//
+CRsfwFileEntry* CRsfwFileEntry::Lookup(const TFid& aFid)
+    {
+    // linear search - immediate kids first
+    TInt i;
+    for (i = 0; i < iKids.Count(); i++)
+        {
+        CRsfwFileEntry* fep = iKids[i];
+        if (fep->Fid().iNodeId == aFid.iNodeId)
+            {
+            return iKids[i];
+            }
+        }
+    // Not found - lookup the kids' kids 
+    for (i = 0; i < iKids.Count(); i++)
+        {
+        CRsfwFileEntry* fep;
+        fep = iKids[i]->Lookup(aFid);
+        if (fep)
+            {
+            return fep;
+            }
+        }
+    return NULL;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::SetLockedL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::SetLockedL(CRsfwLockManager* lockManager, TDesC8* aLockToken)
+    {
+    DEBUGSTRING16(("Set locked: marking file '%S' locked", Name()));
+    if (iLockTimeout > 0)
+        {
+        if (!iLockTimer)
+            {
+            iLockTimer = CPeriodic::NewL(CActive::EPriorityHigh);
+            }
+
+        // attempt to refresh when one third of the timeout has expired
+        TCallBack callBack(CRsfwFileEntry::LockTimerExpiredL, this);
+        iLockTimer->Start(1000000*(iLockTimeout/KLockRefreshAdjustment),
+                          1000000*(iLockTimeout/KLockRefreshAdjustment),
+                          callBack);
+        }
+    iFlags |= KNodeHasValidLock;
+    iLockManager = lockManager;
+    iLockManager->AddLockedEntryL(this);
+    if (aLockToken)
+        {
+        // We were not just refreshing the lock
+        delete iLockToken;
+        iLockToken = aLockToken;
+        }
+    ReportEvent(KNotifyNodeModified);
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::RemoveLocked
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::RemoveLocked()
+    {
+    DEBUGSTRING16(("Remove locked: marking file '%S' unlocked", Name()));
+    if (iFlags & KNodeHasValidLock)
+        {
+        iLockManager->RemoveLockedEntry(this);
+        iLockManager = NULL; // will be set in SetLockedL, if needed once again
+        iFlags &= ~KNodeHasValidLock;
+       ReportEvent(KNotifyNodeModified);
+        }
+    
+    if (iLockToken) 
+        {
+        delete iLockToken;
+        iLockToken = NULL;
+        }
+    if (iLockTimer) 
+        {
+        delete iLockTimer;
+        iLockTimer = NULL;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::LockTimerExpiredL
+// ----------------------------------------------------------------------------
+//
+TInt CRsfwFileEntry::LockTimerExpiredL(TAny* aParam)
+    {
+    CRsfwFileEntry* fe = static_cast<CRsfwFileEntry*>(aParam);
+    DEBUGSTRING16(("Lock timer expired for '%S'", fe->Name()));
+    fe->iLockManager->RefreshLockL(fe);
+    return KErrNone;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::UseCachedData
+// ----------------------------------------------------------------------------
+//
+TBool CRsfwFileEntry::UseCachedData()
+    {
+    // now meta data should tell us whether to use cached data or not
+    return iUseCachedData && !RemotelyDirty();
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::SetAttribValidationTime
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::SetAttribValidationTime()
+    {
+    iAttribValidation.UniversalTime();
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::ExternalizeL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::ExternalizeL(RWriteStream& aStream) const
+    {
+    DEBUGSTRING16(("CRsfwFileEntry::ExternalizeL for node %d", iFid.iNodeId));
+    DEBUGSTRING16(("iFlags: %d", &iFlags));
+    // The node Id must be the first entry
+
+    // iNodeId, iParentNodeId, iType, iSize, iAtt, iModified, iFlags,
+    // iCachedSize, iCachePriority
+    // iCacheName, iName, iMimeType,
+    // iOpaqueFileId, iLockToken
+
+    aStream.WriteInt32L(iFid.iNodeId);
+    if (iParent)
+        {
+        aStream.WriteUint32L(iParent->Fid().iNodeId);
+        }
+    else
+        {
+        // Root
+        aStream.WriteUint32L(0);
+        }
+    aStream.WriteUint8L(iType);
+    aStream.WriteInt32L(iSize);
+    aStream.WriteUint32L(iAtt);
+    aStream.WriteUint32L(I64HIGH(iModified.Int64()));
+    aStream.WriteUint32L(I64LOW(iModified.Int64()));
+    aStream.WriteUint32L(iFlags);
+    aStream.WriteInt32L(iCachedSize);
+    aStream.WriteInt32L(iCachePriority);
+    aStream.WriteInt32L(iUseCachedData);
+    aStream << iCacheName;
+
+    HBufC* null = HBufC::NewLC(0);
+    if (iName)
+        {
+        aStream << *iName;
+        }
+    else
+        {
+        aStream << *null;
+        }
+
+    if (iMimeType)
+        {
+        aStream << *iMimeType;
+        }
+    else
+        {
+        aStream << *null;
+        }
+
+    if (iOpaqueFileId)
+        {
+        aStream << *iOpaqueFileId;
+        }
+    else
+        {
+        aStream << *null;
+        }
+
+    if (iLockToken)
+        {
+        aStream << *iLockToken;
+        }
+    else
+        {
+        aStream << *null;
+        }
+
+    CleanupStack::PopAndDestroy(null); // null
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::InternalizeL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::InternalizeL(RReadStream& aStream)
+    {
+    DEBUGSTRING16(("CRsfwFileEntry::InternalizeL for node %d", iFid.iNodeId));
+    // iNodeId, iParentNodeId, iType, iSize, iAtt, iModified, iFlags,
+    // iCachedSize, iCachePriority
+    // iCacheName, iName, iMimeType,
+    // iOpaqueFileId, iLockToken
+    
+    // make some basic checking whether data being internalized is correct
+    iFid.iNodeId = aStream.ReadInt32L();
+    if (iFid.iNodeId < 0)
+        {
+        User::Leave(KErrCorrupt);
+        }
+    iParentNodeId = aStream.ReadInt32L();
+    if (iParentNodeId < 0)
+        {
+        User::Leave(KErrCorrupt);
+        }
+    iType = aStream.ReadUint8L();
+    iSize = aStream.ReadInt32L();
+    if (iSize < 0)
+        {
+        User::Leave(KErrCorrupt);
+        }    
+    iAtt = aStream.ReadUint32L();
+    TInt highTime = aStream.ReadUint32L();
+    TInt lowTime = aStream.ReadUint32L();
+    iModified = MAKE_TINT64(highTime, lowTime);
+    iFlags = aStream.ReadUint32L();
+    DEBUGSTRING16(("iFlags: %d", &iFlags));
+    iCachedSize = aStream.ReadInt32L();
+    if (iCachedSize < 0)
+        {
+        User::Leave(KErrCorrupt);
+        }
+    iCachePriority = aStream.ReadInt32L();
+    iUseCachedData = aStream.ReadInt32L();
+    aStream >> iCacheName;
+
+    HBufC* buf = HBufC::NewL(aStream, KMaxPath);
+    if (buf->Length())
+        {
+        iName = buf;
+        }
+    else
+        {
+        delete buf;
+        buf = NULL;
+        }
+
+    // MimeType
+    HBufC8* buf8 = HBufC8::NewL(aStream, KMaxPath);
+    if (buf8->Length())
+        {
+        iMimeType = buf8;
+        }
+    else
+        {
+        delete buf8;
+        }
+
+    // OpaqueFileId
+    buf8 = HBufC8::NewL(aStream, KMaxPath);
+    if (buf8->Length())
+        {
+        iOpaqueFileId = buf8;
+        }
+    else
+        {
+        delete buf8;
+        }
+
+    // LockToken
+    buf8 = HBufC8::NewL(aStream, KMaxPath);
+    if (buf8->Length())
+        {
+        iLockToken = buf8;
+        }
+    else
+        {
+        delete buf8;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::SetType
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::SetType(TUint8 aType)
+    {
+    TUint8 oldType = iType;
+    iType = aType;
+    if (aType == KNodeTypeDir)
+        {
+        iAtt |= KEntryAttDir;
+        }
+    else
+        {
+        iAtt &= ~KEntryAttDir;
+        }
+    if (iType != oldType)
+        {
+        ReportEvent(KNotifyNodeModified);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::SetSize
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::SetSize(TInt aSize)
+    {
+    TInt oldSize = iSize;
+    iSize = aSize;
+    if (iSize != oldSize)
+        {
+        ReportEvent(KNotifyNodeModified);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::SetModified
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::SetModified(const TTime& aModified)
+    {
+    TTime oldModified = iModified;
+    iModified = aModified;
+    if (iModified != oldModified)
+        {
+        ReportEvent(KNotifyNodeModified);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::SetAtt
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::SetAtt(TUint aAtt)
+    {
+    // Don't change caching and protected state
+    TUint oldAtt = iAtt;
+    if (IsFullyCached())
+        {
+        aAtt &= ~KEntryAttRemote;
+        }
+    else
+        {
+        aAtt |= KEntryAttRemote;
+        }
+    iAtt = aAtt;
+
+    // Set node type
+    if (iAtt & KEntryAttDir)
+        {
+        iType = KNodeTypeDir;
+        }
+    else
+        {
+        iType = KNodeTypeFile;
+        }
+
+    if (iAtt != oldAtt)
+        {
+        ReportEvent(KNotifyNodeModified);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::SetMimeTypeL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::SetMimeTypeL(const TDesC8& aMimeType)
+    {
+    if (iMimeType)
+        {
+        delete iMimeType;
+        iMimeType = NULL;
+        }
+    if (aMimeType.Length())
+        {
+        iMimeType = aMimeType.AllocL();
+        }
+
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::SetOpaqueFileIdL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::SetOpaqueFileIdL(const TDesC8& aOpaqueFileId)
+    {
+    if (iOpaqueFileId)
+        {
+        delete iOpaqueFileId;
+        iOpaqueFileId = NULL;
+        }
+    if (aOpaqueFileId.Length())
+        {
+        iOpaqueFileId = aOpaqueFileId.AllocL();
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::IsLocallyDirty
+// ----------------------------------------------------------------------------
+//
+TBool CRsfwFileEntry::IsLocallyDirty() const
+    {
+    DEBUGSTRING16(("IsLocallyDirty for file %S", Name()));
+    return (iFlags & KNodeLocallyDirty) != 0;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::IsCancelled
+// ----------------------------------------------------------------------------
+//
+TBool CRsfwFileEntry::IsCancelled() const
+    {
+    DEBUGSTRING16(("CRsfwFileEntry::IsCancelled()"));
+    return (iFlags & KNodeWritingCancelled) != 0;
+    }
+
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::SetLocallyDirty
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::SetLocallyDirty()
+    {
+    DEBUGSTRING16(("SetLocallyDirty for file %S", Name()));
+    TUint oldFlags = iFlags;
+    iFlags |= KNodeLocallyDirty;
+    if (iFlags != oldFlags)
+        {
+        ReportEvent(KNotifyNodeModified);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::ResetLocallyDirty
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::ResetLocallyDirty()
+    {
+    DEBUGSTRING16(("ResetLocallyDirty for file %S", Name()));
+    TUint oldFlags = iFlags;
+    iFlags &= ~KNodeLocallyDirty;
+    if (iFlags != oldFlags)
+        {
+        ReportEvent(KNotifyNodeModified);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::RemotelyDirty
+// ----------------------------------------------------------------------------
+//
+TBool CRsfwFileEntry::RemotelyDirty() const
+    {
+    return (iFlags & KNodeRemotelyDirty) != 0;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::SetRemotelyDirty
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::SetRemotelyDirty()
+    {
+    TUint oldFlags = iFlags;
+    iFlags |= KNodeRemotelyDirty;
+    if (iFlags != oldFlags)
+        {
+        ReportEvent(KNotifyNodeModified);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::ResetRemotelyDirty
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::ResetRemotelyDirty()
+    {
+    TUint oldFlags = iFlags;
+    iFlags &= ~KNodeRemotelyDirty;
+    if (iFlags != oldFlags)
+        {
+        ReportEvent(KNotifyNodeModified);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::IsMarked
+// ----------------------------------------------------------------------------
+//
+TBool CRsfwFileEntry::IsMarked() const
+    {
+    return (iFlags & KNodeMarked) != 0;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::Mark
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::Mark()
+    {
+    // This is transient state (so, it need not be saved persistently)
+    iFlags |= KNodeMarked;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::Unmark
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::Unmark()
+    {
+    iFlags &= ~KNodeMarked;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::SetFlags
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::SetFlags(TUint aFlags)
+    {
+    TUint oldFlags = iFlags;
+    iFlags |= aFlags;
+    if (iFlags != oldFlags)
+        {
+        ReportEvent(KNotifyNodeModified);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::ResetFlags
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::ResetFlags(TUint aFlags)
+    {
+    TUint oldFlags = iFlags;
+    iFlags &= ~aFlags;
+    if (iFlags != oldFlags)
+        {
+        ReportEvent(KNotifyNodeModified);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::SetOpenedForWriting
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::SetOpenedForWriting(TBool aOpenedForWriting)
+    {
+    TUint oldFlags = iFlags;
+    if (aOpenedForWriting)
+        {
+        DEBUGSTRING(("CRsfwFileEntry::SetOpenedForWriting TRUE"));
+        iFlags |= KNodeOpenedForWriting;
+        }
+    else
+        {
+        DEBUGSTRING(("CRsfwFileEntry::SetOpenedForWriting FALSE"));
+        iFlags &= ~KNodeOpenedForWriting;
+        }
+    if (iFlags != oldFlags)
+        {
+        ReportEvent(KNotifyNodeModified);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::IsOpenedForWriting
+// ----------------------------------------------------------------------------
+//
+TBool CRsfwFileEntry::IsOpenedForWriting() const
+    {
+    DEBUGSTRING(("CRsfwFileEntry::IsOpenedForWriting"));
+    return (iFlags & KNodeOpenedForWriting) != 0;
+    }
+     
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::SetNewlyCreated
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::SetNewlyCreated()
+    {
+    iFlags |= KNodeNewlyCreated;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::ResetNewlyCreated
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::ResetNewlyCreated()
+    {
+    iFlags &= ~KNodeNewlyCreated;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::IsNewlyCreated
+// ----------------------------------------------------------------------------
+//
+TBool CRsfwFileEntry::IsNewlyCreated() const
+    {
+    return (iFlags & KNodeNewlyCreated) != 0;
+    }
+
+    
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::IsLocked
+// ----------------------------------------------------------------------------
+//
+TBool CRsfwFileEntry::IsLocked() const
+    {
+    return (iFlags & KNodeHasValidLock) != 0;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEntry::ReportEvent
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEntry::ReportEvent(TInt aEvent)
+    {
+    // If there is no file table,
+    // this is a transient entry
+    if (iFileTable && iFileTable->Permanence())
+        {
+        iFileTable->HandleMetaDataEvent(aEvent, this);
+        }
+    }
+
+
+void CRsfwFileEntry::ResolveDirtyFilesL() 
+    {
+    DEBUGSTRING(("CRsfwFileEntry::ResolveDirtyFilesL"));
+    if (this->Type() == KNodeTypeDir)
+        {
+        for (int i = 0; i < iKids.Count(); i++)
+            {
+            iKids[i]->ResolveDirtyFilesL();
+            }        
+        }
+    else  if (this->Type() == KNodeTypeFile)
+        {
+        // this is a leaf
+        iFileTable->ResolveDirtyFileL(this);
+        }
+
+    }