remotestoragefw/remotefileengine/src/rsfwfileengine.cpp
branchRCL_3
changeset 20 1aa8c82cb4cb
parent 0 3ad9d5175a89
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/remotestoragefw/remotefileengine/src/rsfwfileengine.cpp	Wed Sep 01 12:15:08 2010 +0100
@@ -0,0 +1,1763 @@
+/*
+* 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:  Operation independent remote file handling functions
+*
+*/
+
+
+#include <apgcli.h>
+#include <bautils.h>
+
+#include "rsfwfileentry.h"
+#include "rsfwfiletable.h"
+#include "rsfwvolumetable.h"
+#include "rsfwvolume.h"
+#include "rsfwrfestatemachine.h"
+#include "rsfwinterface.h"
+#include "rsfwcontrol.h"
+#include "rsfwremoteaccess.h"
+#include "rsfwfileengine.h"
+#include "rsfwrfeserver.h"
+#include "rsfwlockmanager.h"
+#include "mdebug.h"
+#include "rsfwdirent.h"
+#include "rsfwdirentattr.h"
+#include "rsfwinterface.h"
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::NewL
+// ----------------------------------------------------------------------------
+//
+CRsfwFileEngine* CRsfwFileEngine::NewL(CRsfwVolume* aVolume)
+    {
+    CRsfwFileEngine* self = CRsfwFileEngine::NewLC(aVolume);
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::NewLC
+// ----------------------------------------------------------------------------
+//
+CRsfwFileEngine* CRsfwFileEngine::NewLC(CRsfwVolume* aVolume)
+    {
+    DEBUGSTRING(("CRsfwFileEngine::NewLC"));
+    CRsfwFileEngine* self = new (ELeave) CRsfwFileEngine();
+    DEBUGSTRING(("CRsfwFileEngine: in NewLC 0x%x", self));
+    CleanupStack::PushL(self);
+    self->ConstructL(aVolume);
+    return self;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::ConstructL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::ConstructL(CRsfwVolume* aVolume)
+    {
+    iRemoteAccess = NULL;
+    iRootFid = NULL;
+    iRootFep = NULL;
+    iVolume = aVolume;
+    iFs = CRsfwRfeServer::Env()->iFs;
+    iConnectionState = KMountNotConnected;
+    __ASSERT_ALWAYS(iVolume != NULL, User::Panic(KRfeServer, EConstructingServerStructs));
+    iInactivityTimeout =
+       iVolume->iMountInfo.iMountConfig.iInactivityTimeout * 1000000;
+    PrepareCacheL();
+    // Create file table
+    iFileTable = CRsfwFileTable::NewL(aVolume, iCacheRoot);
+    __ASSERT_ALWAYS(iVolume->iVolumeTable != NULL, User::Panic(KRfeServer, 
+    			EConstructingServerStructs));
+    SetupRootL(iVolume->iVolumeTable->iPermanence);
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::~CRsfwFileEngine
+// ----------------------------------------------------------------------------
+//
+CRsfwFileEngine::~CRsfwFileEngine()
+    {
+    DEBUGSTRING(("CRsfwFileEngine destructor"));
+    delete iFileTable;
+    delete iRemoteAccess;
+    delete iLockManager;
+    StopInactivityTimer();
+    delete iInactivityTimer;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::DispatchL
+// we should only come here with some synchronous requests
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::DispatchL(TRfeInArgs& aIn, TRfeOutArgs& aOut)
+    {
+
+    switch(aIn.iOpCode)
+        {
+    case EFsIoctl:
+        DEBUGSTRING(("IOCTL"));
+        DoIoctlL(static_cast<TRfeIoctlInArgs&>(aIn),
+                 aOut);
+        break;
+
+    case EFsRoot:
+        DEBUGSTRING(("ROOT"));
+        DoRootL(static_cast<TRfeRootInArgs&>(aIn),
+                static_cast<TRfeRootOutArgs&>(aOut));
+        break;
+
+    case ESetAttr:
+        DEBUGSTRING(("SETATTR"));
+        DoSetAttrL(static_cast<TRfeSetAttrInArgs&>(aIn),
+                   aOut);
+        break;
+
+    default:
+        DEBUGSTRING(("WHAT??? - %d", aIn.iOpCode));
+        User::Leave(KErrArgument);
+        break;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::FullNameLC
+// ----------------------------------------------------------------------------
+//
+HBufC* CRsfwFileEngine::FullNameLC(CRsfwFileEntry& aFe)
+    {
+    HBufC* fn = aFe.FullNameLC();
+    return fn;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::FullNameL
+// ----------------------------------------------------------------------------
+//
+HBufC* CRsfwFileEngine::FullNameL(CRsfwFileEntry& aFe)
+    {
+    HBufC* fn = FullNameLC(aFe);
+    CleanupStack::Pop(fn);
+    return fn;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::SetupAttributes
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::SetupAttributes(CRsfwFileEntry& aFe)
+    {
+    DEBUGSTRING(("CRsfwFileEngine::SetupAttributes"));
+    // Construct the attributes for a newly created file or directory,
+    // or a file that that was locally modified and just written to the server,
+    // based on local knowledge of time and file size.
+    // We assume that either the file is cached or it is an empty file.
+    // We do not touch the local or protection attributes.
+
+    TUint att;
+
+    // Assume that the file type has already been setup
+    if (aFe.Type() == KNodeTypeDir)
+        {
+        att = KEntryAttDir;
+        }
+    else
+        {
+        att = 0;
+        }
+
+    TTime time;
+    if (aFe.IsCached())
+        {
+        TDesC* cacheNamep = aFe.CacheFileName();
+        RFile f;
+        if (f.Open(iFs, *cacheNamep, EFileShareAny) == KErrNone)
+            {
+            // attribute bits
+            TUint a;
+            f.Att(a);
+
+            att |= a & KEntryAttReadOnly;
+
+            if (aFe.Type() == KNodeTypeDir)
+                {
+                aFe.SetSize(0);
+                }
+            else
+                {
+                if (aFe.IsFullyCached())
+                    {
+                    // size
+                    TInt siz;
+                    f.Size(siz);
+                    DEBUGSTRING(("File is fully cached, setting size to %d", siz));
+                    aFe.SetSize(siz);
+                    aFe.SetCachedSize(siz);
+                    }
+                else
+                	{
+                	DEBUGSTRING(("File is not fully cached, not touching the size"));
+                	// file is not fully cached
+                	// the size cannot be set from the local cache container	
+                	}
+                }
+            // modification time
+            f.Modified(time);
+
+            f.Close();
+            aFe.iUseCachedData = ETrue;
+          }
+        else 
+          {
+          // No cache
+          aFe.SetSize(0);
+          time.HomeTime();        
+          }
+        
+        }
+    else
+        {
+        // No cache
+        aFe.SetSize(0);
+        time.HomeTime();
+        }
+
+    aFe.SetAtt(att);
+
+    aFe.SetModified(time);
+    aFe.SetAttribValidationTime();
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::MakeDirectoryEntry
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::MakeDirectoryEntry(CRsfwFileEntry& aFe, TDirEnt& aDirEnt)
+    {
+    DEBUGSTRING(("CRsfwFileEngine::MakeDirectoryEntry"));
+    DEBUGSTRING16(("name %S, att %d, size %d", aFe.Name(), aFe.Att(), aFe.Size()));;
+    aDirEnt.Clear();
+    aDirEnt.iName.Copy(*aFe.Name());
+    aDirEnt.iAttr.iAtt = aFe.Att();
+    aDirEnt.iAttr.iSize = aFe.Size();
+    aDirEnt.iAttr.iModified = aFe.Modified();
+    aDirEnt.iAttr.iUid3 = aFe.iUid;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::UpdateDirectoryContainerL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::UpdateDirectoryContainerL(CRsfwFileEntry& aFe)
+    {
+    // Construct the directory container based on
+    // file table information
+    DEBUGSTRING16(("Update directory container of %d (%S)", aFe.Fid().iNodeId, aFe.Name()));
+
+    TDesC* cacheNamep = aFe.CacheFileName();
+    if (!cacheNamep)
+        {
+        // There was no prior cache.
+        DEBUGSTRING(("Cache missing!"));
+        User::Leave(KErrGeneral);
+        }
+
+    RFile f;
+    CleanupClosePushL(f);
+    User::LeaveIfError(f.Replace(iFs,
+                                 *cacheNamep,
+                                 EFileShareAny | EFileWrite));
+    RFileWriteStream fStream(f);
+    CleanupClosePushL(fStream);
+
+    RPointerArray<CRsfwFileEntry>* kidsp = aFe.Kids();
+    TInt i;
+    if (!(iVolume->iVolumeTable->EnsureCacheCanBeAddedL(
+              sizeof(TEntry) * kidsp->Count())))      
+        {   // pessimistic estimate
+        User::Leave(KErrDiskFull);
+        }
+    for (i = 0; i < kidsp->Count(); i++)
+        {
+        CRsfwFileEntry* kidFep = (*kidsp)[i];
+        TDirEnt dirEnt;
+        MakeDirectoryEntry(*kidFep, dirEnt);
+        dirEnt.ExternalizeL(fStream);      
+        }
+    CleanupStack::PopAndDestroy(2, &f); // f
+
+    aFe.ResetLocallyDirty();
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::DataChanged
+// ----------------------------------------------------------------------------
+//
+TInt CRsfwFileEngine::DataChanged(const CRsfwDirEntAttr& aOldAttr,
+                              const CRsfwDirEntAttr& aNewAttr)
+    {
+    // Based on attributes or metadata in general,
+    // tell whether the actual data, if cached,
+    // should be updated
+    if (aOldAttr.Att() == KEntryAttDir)
+        {
+        // use Last Modified (a weak entity tag)
+        if (aOldAttr.Modified() == aNewAttr.Modified())
+            {
+            return EFalse;
+            }
+        else
+            {
+            return ETrue;
+            }
+        }
+    else
+        {
+        // use ETags if available
+        // a strong entity tag
+        if (aOldAttr.ETag() && aNewAttr.ETag())
+            {
+            if (*aOldAttr.ETag() == *aNewAttr.ETag())
+                {
+                return EFalse;
+                }
+            else
+                {
+                return ETrue;
+                }
+            }
+
+        // use Last Modified (a weak entity tag)
+        // we assume it's file and compare also iSize...
+        if ((aOldAttr.Modified() == aNewAttr.Modified()) &&
+            (aOldAttr.Size() == aNewAttr.Size()))
+            {
+            return EFalse;
+            }
+        else
+            {
+            return ETrue;
+            }
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::UseCachedData
+// ----------------------------------------------------------------------------
+//
+TBool CRsfwFileEngine::UseCachedData(CRsfwFileEntry& aFe)
+    {
+    if (!Disconnected())
+        {
+        return aFe.UseCachedData();
+        }
+    else
+        {
+        return ETrue;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::UseCachedAttributes
+// ----------------------------------------------------------------------------
+//
+TBool CRsfwFileEngine::UseCachedAttributes(CRsfwFileEntry& aFe)
+    {
+      if (!Disconnected())
+        {
+        if (aFe.Type() == KNodeTypeDir)
+			{
+			return iFileTable->Volume()->iVolumeTable->
+				IsCachedAttrStillValid(aFe.iAttribValidation);
+			}
+		else
+			{ // file
+			return iFileTable->Volume()->iVolumeTable->
+				IsCachedDataStillValid(aFe.iAttribValidation);
+
+			}
+        }
+    else
+        {
+        return ETrue;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::GetAttributesL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::GetAttributesL(CRsfwFileEntry& aFe,
+                                 CRsfwDirEntAttr*& aAttr,
+                                 TUint aNodeType,
+                                 CRsfwRfeStateMachine* aCaller)
+    {
+    // Gets attributes for File Entry aFe.
+    // Uses either cached attributes (if they are still deemed to be valid), or
+    // fetches the attributes from the server*/
+    DEBUGSTRING(("GetAttributesL"));
+    if ((aFe.Type() == aNodeType) && UseCachedAttributes(aFe))
+        {
+        // Nothing to do
+
+        if (aFe.IsOpenedForWriting())
+            {
+            // update attributes when we are writing to the file
+            DEBUGSTRING(("volatile attributes"));
+            SetupAttributes(aFe);
+            }
+        else
+            {
+            DEBUGSTRING(("using cached attributes"));
+            }
+        aCaller->HandleRemoteAccessResponse(0, KErrNone); // "file exists"
+        }
+    else
+        {
+        // Refresh attributes
+        UpdateAttributesL(aFe, aAttr, aNodeType, aCaller);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::UpdateAttributesL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::UpdateAttributesL(CRsfwFileEntry& aFe,
+                                    CRsfwDirEntAttr*& aAttr,
+                                    TUint aNodeType,
+                                    MRsfwRemoteAccessResponseHandler* aCaller)
+    {
+    // UpdateAttributes doesn't attempt to use cached attributes
+    HBufC* path = FullNameLC(aFe);
+    TPtr p = path->Des();
+    DEBUGSTRING16(("UpdateAttributesL of '%S'", &p));
+
+
+    UpdateAttributesL(*path, aAttr, aNodeType, aCaller);
+
+    CleanupStack::PopAndDestroy(path); // path
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::UpdateAttributesL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::UpdateAttributesL(TDesC& aPath,
+                                    TDesC& aName,
+                                    CRsfwDirEntAttr*& aAttr,
+                                    TUint aNodeType,
+                                    MRsfwRemoteAccessResponseHandler* aCaller)
+    {
+    HBufC* pn = HBufC::NewLC(KMaxPath);
+    TPtr pnPtr = pn->Des();
+
+    if (aPath.Length())
+        {
+        pnPtr.Copy(aPath);
+        pnPtr.Append('/');
+        }
+    pnPtr.Append(aName);
+
+    DEBUGSTRING16(("UpdateKidAttributes of '%S'", &pnPtr));
+
+   	UpdateAttributesL(pnPtr, aAttr, aNodeType, aCaller);
+
+    CleanupStack::PopAndDestroy(pn);
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::UpdateAttributesL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::UpdateAttributesL(TDesC& aFullPath,
+                                    CRsfwDirEntAttr*& aAttr,
+                                    TUint aNodeType,
+                                    MRsfwRemoteAccessResponseHandler* aCaller)
+	{
+
+	// If we have "recently" found out that this file/dir does NOT exist
+	// we cache even this negative result. Time limit is cache expiry for
+	// directory attributes
+	 if ((aFullPath.Length() > 0) &&    // do not compare root folder (always exists)
+	 (iLastFailedLookup == aFullPath) &&
+	 	  (iFileTable->Volume()->iVolumeTable->
+				IsCachedAttrStillValid(iLookupTime)))
+    	{
+    	if (aNodeType == KNodeTypeDir)
+            {
+            aCaller->HandleRemoteAccessResponse(0, KErrPathNotFound);
+            }
+        else if (aNodeType == KNodeTypeFile)
+            {
+            aCaller->HandleRemoteAccessResponse(0, KErrNotFound);
+            }
+        return;
+
+    	}
+
+	if (!Disconnected())
+        {
+        if (aNodeType == KNodeTypeDir)
+            {
+            RemoteAccessL()->GetDirectoryAttributesL(aFullPath, aAttr, aCaller);
+            }
+        else if (aNodeType == KNodeTypeFile)
+            {
+            RemoteAccessL()->GetFileAttributesL(aFullPath, aAttr, aCaller);
+            }
+        }
+    else
+        {
+        User::Leave(KErrNotFound);
+        }
+
+	}
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::CreateContainerFileL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::CreateContainerFileL(CRsfwFileEntry& aFe)
+    {
+    // Create a container file for the Fid.
+    // If the cache file already exists, it will be deleted
+
+    RFile f;
+    HBufC* cachePath = HBufC::NewMaxLC(KMaxPath);
+    TPtr pathPtr = cachePath->Des();
+    BuildContainerPathL(aFe, pathPtr);
+
+    TInt err = f.Replace(iFs, *cachePath, EFileShareAny | EFileWrite);
+    f.Close();
+    if (err != KErrNone)
+        {
+        DEBUGSTRING(("Error when creating container file! err=%d", err));
+        User::Leave(KErrGeneral);
+        }  
+    aFe.SetCacheFileName(cachePath);
+    CleanupStack::PopAndDestroy(cachePath);
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::FetchAndCacheL
+// ----------------------------------------------------------------------------
+//
+TUint CRsfwFileEngine::FetchAndCacheL(CRsfwFileEntry& aFe,
+                                  TInt aFirstByte,
+                                  TInt* aLength,
+                                  RPointerArray<CRsfwDirEnt>* aDirEntsp,
+                                  CRsfwRfeStateMachine* aCaller)
+    {
+    // Fetch a file from the remote store and decrypt it if necessary.
+    // The assumption is that the file has not yet been fetched
+    // or has been cached up to the byte indicated by (aFe.iCachedSize - 1)
+    // and filling the cache will continue linearly
+    // i.e. aFirstByte = 0 || aFirstByte = aFe.iCachedSize
+    // Access modules can fetch more than requested, so aLastByte might change.
+
+    DEBUGSTRING(("Fetch fid %d, bytes %d - %d",
+                 aFe.Fid().iNodeId,
+                 aFirstByte,
+                 aFirstByte + *aLength));
+
+    TUint transactionId = 0;
+    RFile f;
+    HBufC* fullName = NULL;
+    HBufC* cacheName = HBufC::NewMaxLC(KMaxPath);
+    TPtr cachePtr = cacheName->Des();
+    TInt err;
+    
+    TInt usedCache = iVolume->iVolumeTable->TotalCachedSize();
+
+    // This much will be added to the cache by this fetch
+    if (!iVolume->iVolumeTable->EnsureCacheCanBeAddedL(*aLength))
+        {
+        User::Leave(KErrDiskFull);
+        }
+
+    if (!Disconnected())
+        {
+        if (aFe.CacheFileName())
+            {
+            // modify an existing cachefile ...
+            cachePtr = *(aFe.CacheFileName());
+
+            if (aFe.Type() == KNodeTypeFile)
+                {
+                // If the cache file exists,
+                // we will just continue filling it...
+                err = f.Open(iFs, *cacheName, EFileShareAny | EFileWrite);
+                if (err)
+                    {
+                    User::LeaveIfError(f.Replace(iFs,
+                                                 *cacheName,
+                                                 EFileShareAny | EFileWrite));
+                    }
+                }
+            else
+                {
+                User::LeaveIfError(f.Replace(iFs,
+                                             *cacheName,
+                                             EFileShareAny | EFileWrite));
+                }      
+            }
+        else
+            {
+            // create a new cache file
+            CreateContainerFileL(aFe, cachePtr, f);
+            }
+
+        CleanupClosePushL(f);
+        fullName = FullNameLC(aFe);
+        if (aFe.Type() == KNodeTypeDir)
+            {
+            transactionId = GetDirectoryL(aFe,
+                                          *fullName,
+                                          f,
+                                          aDirEntsp,
+                                          aCaller);
+            }
+        else if (aFe.Type() == KNodeTypeFile)
+            {
+            f.Close();
+            transactionId = RemoteAccessL()->GetFileL(*fullName,
+                                                      *cacheName,
+                                                      aFirstByte,
+                                                      aLength,
+                                                      0,
+                                                      aCaller);
+            }
+
+        // fullName, f (duplicate close in the case of files)
+        CleanupStack::PopAndDestroy(2, &f);
+        }
+    CleanupStack::PopAndDestroy(cacheName);    
+    return transactionId;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::RequestConnectionStateL
+// ----------------------------------------------------------------------------
+//
+TUint CRsfwFileEngine::RequestConnectionStateL(TUint aConnectionState,
+                                           CRsfwRfeStateMachine* aCaller)
+    {
+    DEBUGSTRING16(("CRsfwFileEngine::RequestConnectionStateL %d", aConnectionState));
+    DEBUGSTRING16(("current connection state is %d", iConnectionState));
+    TUint transactionId = 0;
+    if (aConnectionState != iConnectionState)
+        {
+        switch (aConnectionState)
+            {
+        case KMountNotConnected:
+            DisconnectL();
+            break;
+        case KMountStronglyConnected:
+            transactionId = ConnectL(ETrue, aCaller);
+            break;
+
+        default:
+            break;
+            }
+        }
+    // else does not do anything (if iConnectionState == aConnectionState)    
+    return transactionId;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::EnteredConnectionStateL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::EnteredConnectionStateL(TUint aConnectionState,
+                                          TBool aRequested)
+    {
+    DEBUGSTRING16(("CRsfwFileEngine::EnteredConnectionStateL %d", aConnectionState));
+    DEBUGSTRING16(("current connection state is %d", iConnectionState));
+    if (aConnectionState != iConnectionState)
+        {
+        iConnectionState = aConnectionState;
+        iVolume->ConnectionStateChanged(iConnectionState);
+
+        switch (aConnectionState)
+            {
+        case KMountNotConnected:
+            if (!aRequested)
+                {
+                iRemoteAccess->Cancel(0);
+                }
+            break;
+
+        case KMountStronglyConnected:
+            if (aRequested)
+                {
+                if (iLockManager)
+                    {
+                    iLockManager->PopulateExternalLockTokenCacheL(iRootFep);
+                    }
+                }
+            break;
+
+        default:
+            break;
+            }
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::ConnectionState
+// ----------------------------------------------------------------------------
+//
+TUint CRsfwFileEngine::ConnectionState()
+    {
+    return iConnectionState;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::LockManager
+// ----------------------------------------------------------------------------
+//
+CRsfwLockManager* CRsfwFileEngine::LockManager()
+    {
+    return iLockManager;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::SetPermanenceL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::SetPermanenceL(TBool aPermanence)
+    {
+    iFileTable->SetPermanenceL(aPermanence);
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::Disconnected
+// ----------------------------------------------------------------------------
+//
+TBool CRsfwFileEngine::Disconnected()
+    {
+    return (iConnectionState == KMountNotConnected);
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::WriteDisconnected
+// ----------------------------------------------------------------------------
+//
+TBool CRsfwFileEngine::WriteDisconnected()
+    {
+    // This also encompasses disconnected mode
+    return (iConnectionState != KMountStronglyConnected);
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::AddToCacheL
+// ----------------------------------------------------------------------------
+//
+TInt CRsfwFileEngine::AddToCacheL(CRsfwFileEntry& aFe,
+                              RPointerArray<CRsfwDirEnt>* aDirEnts,
+                              CRsfwFileEngine *aFileEngine,
+                              TUint cachedSize)
+    {
+    // returns the size of the cached data
+    RFs fs = CRsfwRfeServer::Env()->iFs;
+    TInt err;
+    TInt kidsCount = 0;
+    TInt containerSize = cachedSize;
+    // holds true for files, will be overwritten for directories
+
+    if (aFe.Type() == KNodeTypeDir)
+        {
+        // *********** originally from CRsfwFileEngine::GetDirectoryL()
+        // **********************************************************
+        // Unmark and mark kids only when getdirectory returns KErrNone
+        // otherwise (i.e. KErrUpdateNotRequired) let's just keep
+        // the cached kids...
+        aFe.UnmarkKids();
+
+        RApaLsSession lsSession;
+        User::LeaveIfError(lsSession.Connect());
+        CleanupClosePushL(lsSession);
+
+        RFileWriteStream fStream;
+        // Dump to the local cache
+        User::LeaveIfError(
+            fStream.Open(fs,
+                         *(aFe.CacheFileName()),
+                         EFileWrite | EFileShareAny));
+        CleanupClosePushL(fStream);
+
+        containerSize = fStream.Sink()->SizeL();
+        TInt i;
+        TLex lex;
+        for (i = 0; i < aDirEnts->Count(); i++)
+            {
+		    CRsfwDirEnt* d = (*aDirEnts)[i];
+            TUid appUid;
+            // For each TDirEnt we just read...
+            // ... if the server returned content-type
+            if (d->Attr()->MimeType() && d->Attr()->MimeType()->Length())
+                {
+                err = lsSession.AppForDataType(*(d->Attr()->MimeType()),
+                                               appUid);
+                if (err == KErrNone)
+                    {
+                    d->Attr()->SetUid(appUid);
+                    }
+                }
+
+            d->Attr()->SetAttFlags(KEntryAttRemote);
+            CRsfwFileEntry* kidFep = aFe.FindKidByName(*d->Name());
+            if (kidFep)
+                {
+                // We already know this kid
+                // However we must check whether the kid has been modified
+                CRsfwDirEntAttr* oldAttr = CRsfwDirEntAttr::NewLC();
+                kidFep->GetAttributesL(*oldAttr);
+                if (DataChanged(*oldAttr, *d->Attr()))
+                    {
+                    kidFep->RemoveCacheFile();
+                    }
+                CleanupStack::PopAndDestroy(oldAttr);
+                if (kidFep->IsFullyCached())
+                    {
+                    // Mark the kid as cached
+                    d->Attr()->ResetAttFlags(KEntryAttRemote);
+                    }
+                 // as this entry is "used", move it to the back of metadata LRU list
+                 iVolume->iVolumeTable->MoveToTheBackOfMetadataLRUPriorityListL(kidFep);
+                }
+
+            // As a side effect,
+            // insert this kid into the file table and
+            // set its attributes
+            if (!kidFep)
+                {
+                if (!iVolume->iVolumeTable->EnsureMetadataCanBeAddedL(&aFe))
+                    {
+                    User::Leave(KErrNoMemory);
+                    }
+                kidFep = CRsfwFileEntry::NewL(*d->Name(), &aFe);
+                // Attach the new kid
+                aFileEngine->iFileTable->AddL(kidFep);
+                aFe.AddKid(*kidFep);
+                }
+
+            kidFep->Mark();
+            
+            // set attributes if getting directory listing also supports getting file attributes
+            if (DirectoryListingContainsFileMetadata()) 
+                {
+                kidFep->SetAttributesL(*d->Attr(), ETrue);
+                }
+             else 
+                {
+                kidFep->SetAttributesL(*d->Attr(), EFalse);
+                }
+
+            TDirEnt dirEnt;
+            MakeDirectoryEntry(*kidFep, dirEnt);
+            dirEnt.ExternalizeL(fStream);
+            kidsCount++;
+            }
+
+        aFe.DropUnmarkedKidsL();
+
+        containerSize = fStream.Sink()->SizeL();
+        // assumes that this fetch will write the whole directory,
+        
+        // i.e. there is no partial fetching for the directories
+        if(!iFileTable->Volume()->iVolumeTable->
+           EnsureCacheCanBeAddedL(containerSize))
+            {
+            User::Leave(KErrDiskFull);
+            }
+        fStream.CommitL();
+
+        CleanupStack::PopAndDestroy(2, &lsSession); // fStream, lsSession
+
+        // if the directory appeared to be childless add it to metadata LRU list
+        if ( aDirEnts->Count() == 0 )
+            {
+            iVolume->iVolumeTable->AddToMetadataLRUPriorityListL(&aFe, ECachePriorityNormal);
+            }
+
+        }// if directory
+
+    // assumes the files are cached in continuos chunks,
+    // i.e. always cached up to the last byte fetched
+    aFe.SetCachedSize(containerSize);
+
+    aFe.SetCached(ETrue);
+
+    // We have to update locally dirty bit for the parent container
+    if (aFe.Parent())
+        {
+        aFe.Parent()->SetLocallyDirty();
+        }
+    // But the object itself cannot be remotely dirty any more
+    aFe.ResetRemotelyDirty();
+
+    // *** from CRsfwFileEngine::DoFetch ***
+    if (aFe.Type() == KNodeTypeDir)
+        {
+        // the reason why kidsCount may be different than aFe.Kids.Count is that for big directories
+        // some kids could have been removed when adding the others to memory. this is due to memory management cap.
+        // however this should not happen so often
+        aFe.KidsCount() == kidsCount ? aFe.iUseCachedData = ETrue : aFe.iUseCachedData = EFalse;
+        }
+    else
+        {
+        aFe.iUseCachedData = ETrue;
+        }
+
+    return containerSize;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::RemoteAccessL
+// ----------------------------------------------------------------------------
+//
+CRsfwRemoteAccess* CRsfwFileEngine::RemoteAccessL()
+    {
+    DEBUGSTRING(("CRsfwFileEngine::RemoteAccessL"));
+    if (!iRemoteAccess)
+        {
+        User::Leave(KErrNotReady);
+        }
+
+    // Prevent the inactivity timer from triggering
+    // in the middle of a remote access operation
+    StopInactivityTimer();
+
+    return iRemoteAccess;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::OperationCompleted
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::OperationCompleted()
+    {
+    DEBUGSTRING(("File engine operation completed"));
+    if (iVolume->iVolumeTable->iPermanence)
+        {
+        iFileTable->SaveMetaDataDelta();
+        }
+        
+    if (iLockManager && (iLockManager->LockedCount() == 0))
+        {
+        // Start timer only if we don't have files open for writing
+        StartInactivityTimer();
+        }
+
+    iVolume->OperationCompleted();
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::CancelTransaction
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::CancelTransaction(TUint iTransactionId)
+    {
+    DEBUGSTRING(("CRsfwFileEngine::CancelTransactionL"));
+    if (iRemoteAccess) 
+        {
+        iRemoteAccess->Cancel(iTransactionId);
+        }
+
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::CancelTransaction
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::CancelTransactionL(TDesC& aPathName)
+    {
+    DEBUGSTRING(("CRsfwFileEngine::CancelTransactionL"));
+    TPtrC testPtr;
+    testPtr.Set(aPathName.Right(aPathName.Length() - 3));
+    HBufC* cancelPath = HBufC::NewLC(KMaxPath);
+    TPtr cancelPathPtr = cancelPath->Des();
+    // change '\\' to '/' so the path matches
+    TLex parser(testPtr);
+    TChar theChar;
+    
+    for (int i = 0; i < testPtr.Length(); i++)
+        {
+        theChar = parser.Get();
+        if (theChar == 0) 
+            {
+            break;
+            }
+        // assumes that the input string always has "\\" and not just "\"
+        // this is true as the input is a file path
+        if (theChar != '\\') 
+            {
+            cancelPathPtr.Append(theChar);
+            }
+        else 
+            {
+            cancelPathPtr.Append('/');
+            }        
+        }
+    
+    if (iRemoteAccess) 
+        {
+        iRemoteAccess->Cancel(*cancelPath);
+        }
+        
+    CleanupStack::PopAndDestroy(cancelPath);    
+    
+    }
+
+    
+
+    
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::SetFailedLookup
+// Caches the last failed lookup result
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::SetFailedLookup(TDesC& aPath, TDesC& aKidName)
+	{
+	iLastFailedLookup = aPath;
+	iLastFailedLookup.Append('/');
+	iLastFailedLookup.Append(aKidName);
+	iLookupTime.HomeTime();
+	DEBUGSTRING16(("SetFailedLookup: %S", &iLastFailedLookup));
+	}
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::ResetFailedLookup
+// Clears the last failed lookup result
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::ResetFailedLookup()
+	{
+	DEBUGSTRING16(("ResetFailedLookup: %S", &iLastFailedLookup));
+	iLastFailedLookup.Zero();
+	}
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::Volume
+// ----------------------------------------------------------------------------
+//
+CRsfwVolume* CRsfwFileEngine::Volume()
+    {
+    return iVolume;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::PrepareCacheL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::PrepareCacheL()
+    {
+    // make sure the file cache (of this volume) exists
+    iCacheRoot.Copy(CRsfwRfeServer::Env()->iCacheRoot);
+    iCacheRoot.Append('C');
+    iCacheRoot.AppendNum(iVolume->iMountInfo.iMountStatus.iVolumeId);
+    iCacheRoot.Append('\\');
+    
+    if (! BaflUtils::FileExists(iFs, iCacheRoot))
+        {
+        // There was no prior cache directory
+        TInt err = iFs.MkDirAll(iCacheRoot);
+        DEBUGSTRING(("Cache directory created with err=%d", err));
+        User::LeaveIfError(err);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::GetDirectoryL
+// ----------------------------------------------------------------------------
+//
+TUint CRsfwFileEngine::GetDirectoryL(CRsfwFileEntry& /*aFe*/,
+                                 TDesC& aFullName,
+                                 RFile& /*aF*/,
+                                 RPointerArray<CRsfwDirEnt>* aDirEntsp,
+                                 MRsfwRemoteAccessResponseHandler* aCaller)
+    {
+    return RemoteAccessL()->GetDirectoryL(aFullName, *aDirEntsp, aCaller);
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::BuildContainerPathL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::BuildContainerPathL(CRsfwFileEntry& aFe, TDes& aPath)
+    {
+    if (aPath.MaxLength() < (aPath.Length() + iCacheRoot.Length()))
+        {
+        aPath.Copy(iCacheRoot);
+        }
+    else 
+        {
+        User::Leave(KErrOverflow);
+        }
+
+    ApplyMultiDirCacheL(aPath);
+    // This filename tagging based on container type is just for convenience
+    if (aFe.Type() == KNodeTypeFile)
+        {
+        aPath.Append('F');
+        }
+    else
+        {
+        aPath.Append('D');
+        }
+    aPath.AppendNum((TInt)aFe.Fid().iNodeId);
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::ApplyMultiDirCachePathL
+// Due to Symbian performance problems with huge directories, items will not
+// be stored in one directory in the cache.
+// Now instead one dir like:
+// C:\system\data\rsfw_cache\C16
+// there will be dirs like:
+// C:\system\data\rsfw_cache\C16\M0
+// C:\system\data\rsfw_cache\C16\M1
+// ... and so on
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::ApplyMultiDirCacheL(TDes& aPath)
+    {
+    // maximum number of items in a single dir in the cache
+    const TInt KRsfwMaxItemsInDir = 100;
+    TInt i;
+    // this loop will surely break (or leave) at some point
+    for ( i = 0; ; i++ )
+        {
+        // create path like "C:\system\data\rsfw_cache\C16\M0"
+        HBufC* trypath = HBufC::NewMaxL(KMaxPath);
+        TPtr pathPtr = trypath->Des();
+        pathPtr.Copy(aPath);
+        pathPtr.Append('M');
+        pathPtr.AppendNum(i);
+        pathPtr.Append('\\');
+
+        // check whether dir exists and if so, how many items it contains
+        CDir* dir = NULL;
+        // note that KEntryAttDir att means files & directories
+        TInt err = iFs.GetDir(*trypath, KEntryAttDir, ESortNone, dir);
+        if ( err == KErrNone )
+            {
+            // count the items
+            TInt count = dir->Count();
+            delete dir;
+            dir = NULL;
+            
+            //limit is not exceeded -> return the path
+            if ( count < KRsfwMaxItemsInDir )
+                {
+                aPath.Copy(pathPtr);
+                delete trypath;
+                break;
+                }
+            // limit exceeded -> let's try the next dir
+            else
+                {
+                delete trypath;
+                continue;
+                }    
+            }        
+        else if ( err == KErrPathNotFound )
+            {
+            // create dir and return the path to empty dir
+            err = iFs.MkDir(*trypath);
+            if (!err) 
+                {
+                aPath.Copy(pathPtr);
+                delete trypath;
+                }
+            else 
+                {
+                delete trypath;
+                DEBUGSTRING(("Error when creating cache dir! err=%d", err));
+                User::Leave(KErrGeneral);
+                }
+   
+            break;
+            }
+        else
+            {
+            delete trypath;
+            DEBUGSTRING(("Cache directory cannot be created! err=%d", err));        
+            User::Leave(KErrGeneral);
+            }    
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::CreateContainerFileL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::CreateContainerFileL(CRsfwFileEntry& aFe,
+                                       TDes& aPath,
+                                       RFile& aF)
+    {
+    // Create a container file for the Fid.
+    // If the cache file already exists, it will be deleted
+
+    BuildContainerPathL(aFe, aPath);
+
+    TInt err = aF.Replace(iFs, aPath, EFileShareAny | EFileWrite);
+    if (err != KErrNone)
+        {
+        User::Leave(KErrGeneral);
+        }
+    aF.Close();
+
+    aFe.SetCacheFileName(&aPath);
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::DoIoctlL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::DoIoctlL(TRfeIoctlInArgs& aIn, TRfeOutArgs& /* aOut */)
+    {
+    TFid fidp = aIn.iFid;
+    TInt cmd = aIn.iCmd;
+
+    TInt err = KErrNone;
+
+    DEBUGSTRING(("ioctl fid %d - command=%d, data=%d",
+                 fidp.iNodeId,
+                 cmd,
+                 aIn.iData32[0]));
+
+    CRsfwFileEntry* fep = iFileTable->Lookup(fidp);
+    if (fep)
+        {
+        switch (cmd)
+            {
+        case ERemoteFsIoctlRefresh:
+
+
+            if (fep->Type() == KNodeTypeFile)
+                {
+
+                fep->SetCacheFileName(NULL);
+                fep->SetCached(EFalse);
+
+                // There is a change in the parent's container
+                fep->Parent()->SetLocallyDirty();
+                }
+            break;
+
+        case ERemoteFsHighCachePriority:
+        default:
+            err = KErrArgument;
+            break;
+            }
+        }
+    else
+        {
+        err = KErrNotFound;
+        }
+
+    if (err != KErrNone)
+        {
+        User::Leave(err);
+        }
+
+    return;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::DoRootL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::DoRootL(TRfeRootInArgs& /* aIn */, TRfeRootOutArgs& aOut)
+    {
+    SetupRootL(iVolume->iVolumeTable->iPermanence);
+    aOut.iFid.iVolumeId = iRootFid->iVolumeId;
+    aOut.iFid.iNodeId = iRootFid->iNodeId;
+    return;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::DoSetAttrL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::DoSetAttrL(TRfeSetAttrInArgs& aIn, TRfeOutArgs& /* aOut */)
+    // We cannot really set anything but this is the way to implement this
+    // note that if this is implemented, it should really be a state machine
+    {
+    TInt err = KErrNone;
+    TFid fidp = aIn.iFid;
+#ifdef _DEBUG
+    TDirEntAttr* attrp = &(aIn.iAttr);
+#endif
+
+    DEBUGSTRING(("setting attributes of fid %d, attr=0x%x, size=%d, time=",
+                 fidp.iNodeId,
+                 attrp->iAtt,
+                 attrp->iSize));
+    DEBUGTIME((attrp->iModified));
+
+    // Get the file or directory to setattr
+    CRsfwFileEntry* fep = iFileTable->Lookup(fidp);
+    if (fep)
+        {
+        err = KErrNotSupported;
+        }
+    else
+        {
+        err = KErrNotFound;
+        }
+
+    User::Leave(err);
+    return;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::SetupRootL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::SetupRootL(TBool aPermanence)
+    {
+    _LIT(KRootPath, ".");  // dummy
+
+    if (!iRootFid)
+        {
+        CRsfwFileEntry* root = NULL;
+        TInt err;
+        if (aPermanence)
+            {
+            TRAP(err, root = iFileTable->LoadMetaDataL());
+            }
+        if (err == KErrCorrupt)    
+            {
+            DEBUGSTRING(("Metadata corrupted! Recreating cache file..."));
+            // corrupted cache file, recreate filetable and cache file
+            delete iFileTable;
+            iFileTable = NULL;
+            CleanupCorruptedCacheL();
+            PrepareCacheL();
+            iFileTable = CRsfwFileTable::NewL(iVolume, iCacheRoot);
+            }
+        if (!aPermanence || (err != KErrNone))
+            {
+            root = CRsfwFileEntry::NewL(KRootPath, NULL);
+            // Insert root into the file table
+            iFileTable->AddL(root);
+            root->SetType(KNodeTypeDir);
+            }
+        if (aPermanence)
+            {
+            iFileTable->SaveMetaDataDelta();
+            }
+        iRootFep = root;
+        iRootFid = &(root->Fid());
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::CleanupCorruptedCacheL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::CleanupCorruptedCacheL()
+    {    
+    // delete everything from the cache
+    TFileName cachepath;
+    cachepath.Copy(iCacheRoot);
+    CFileMan* fileMan = CFileMan::NewL(iFs);
+    fileMan->Delete(cachepath, CFileMan::ERecurse);
+    delete fileMan;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::ConnectL
+// ----------------------------------------------------------------------------
+//
+TUint CRsfwFileEngine::ConnectL(TBool aRestart, CRsfwRfeStateMachine* aCaller)
+    {
+    // Assume parameter format:
+    // protocol://username:password@server:port/rootdir or
+    // The ":password", ":port", and "[/]rootdir" can be omitted.
+    // If the length of password parameter is bigger than 1,
+    // it overrides the one in uri, if any.
+    // Characters can be quoted with %<hexdigit><hexdigit> format
+    TUint transactionId = 0;
+
+    if (iRemoteAccess)
+        {
+        // We already have a remote accessor
+        if (aRestart)
+            {
+            // Restarting
+            delete iLockManager;
+            iLockManager = NULL;
+            delete iRemoteAccess;
+            iRemoteAccess = NULL;
+            }
+        else
+            {
+            User::Leave(KErrAlreadyExists);
+            }
+        }
+
+    DEBUGSTRING16(("ConnectL(): '%S'",
+                   &iVolume->iMountInfo.iMountConfig.iUri));
+
+    TUriParser uriParser;
+    User::LeaveIfError(uriParser.Parse(iVolume->iMountInfo.iMountConfig.iUri));
+
+    TPtrC userName;
+    TPtrC password;
+    TPtrC friendlyName;
+
+    if (uriParser.IsPresent(EUriUserinfo))
+        {
+        TPtrC userInfo(uriParser.Extract(EUriUserinfo));
+        // Split the user info into user name and password (seprated by ':')
+        TInt pos = userInfo.Locate(':');
+        if (pos != KErrNotFound)
+            {
+            password.Set(userInfo.Mid(pos + 1));
+            userName.Set(userInfo.Left(pos));
+            }
+        else
+            {
+            userName.Set(userInfo);
+            }
+        }
+
+    HBufC* userNameBuf = NULL;
+    if (!userName.Length() &&
+        iVolume->iMountInfo.iMountConfig.iUserName.Length())
+        {
+        // separate user name overwrites the username embedded in the URI
+        userName.Set(iVolume->iMountInfo.iMountConfig.iUserName);
+        }
+
+    HBufC* passwordBuf = NULL;
+    if (!password.Length() &&
+        (iVolume->iMountInfo.iMountConfig.iPassword.Length() > 1))
+        {
+        // separate password overwrites the password embedded in the URI
+        password.Set(iVolume->iMountInfo.iMountConfig.iPassword);
+        }
+
+    friendlyName.Set(iVolume->iMountInfo.iMountConfig.iName);
+
+    TPtrC scheme(uriParser.Extract(EUriScheme));
+    HBufC8* protocol = HBufC8::NewLC(scheme.Length());
+    TPtr8 protocolPtr = protocol->Des();
+    protocolPtr.Copy(scheme);
+    iRemoteAccess = CRsfwRemoteAccess::NewL(protocolPtr);
+    CleanupStack::PopAndDestroy(protocol);
+
+    // user name and password are conveyed separately from the URI
+    CUri* uri = CUri::NewLC(uriParser);
+    uri->RemoveComponentL(EUriUserinfo);
+
+    // leaves if error
+    iRemoteAccess->SetupL(this);
+    transactionId = iRemoteAccess->
+        OpenL(uri->Uri(),
+              friendlyName,
+              userName,
+              password,
+              iVolume->iMountInfo.iMountConfig.iAuxData,
+              aCaller);
+
+    CleanupStack::PopAndDestroy(uri);
+    if (passwordBuf)
+        {
+        CleanupStack::PopAndDestroy(passwordBuf);
+        }
+    if (userNameBuf)
+        {
+        CleanupStack::PopAndDestroy(userNameBuf);
+        }
+
+    // lock manager can be created before we know whether connecting was
+    // succesful - however it must be deleted upon unsuccesful connect
+    if (!iLockManager)
+        {
+        iLockManager = CRsfwLockManager::NewL(iRemoteAccess);
+        }
+
+    if ((iInactivityTimeout > 0) && !iInactivityTimer)
+        {
+        iInactivityTimer = CPeriodic::NewL(CActive::EPriorityLow);
+        }
+    return transactionId;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::DisconnectL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::DisconnectL()
+    {
+    DEBUGSTRING(("CRsfwFileEngine::DisconnectL"));
+    if (iRemoteAccess) 
+        {
+        iRemoteAccess->Cancel(0);
+        delete iRemoteAccess;
+        iRemoteAccess = NULL;
+        }
+
+    if (iLockManager) 
+        {
+        delete iLockManager;
+        iLockManager = NULL;
+        }
+
+    
+    // Set open file count to zero
+    // If there are open files, after disconnecting we do not necessarily
+    // get close events.
+    // Note that this variable is not "dirty bit" (file has currently
+    // uncommitted modifications), so it is safe to set it to zero
+    TInt openfiles = iFileTable->OpenFileCount();
+    iFileTable->UpdateOpenFileCount(-openfiles);
+        
+    EnteredConnectionStateL(KMountNotConnected, ETrue);
+    
+    // publish connection status when disconnecting
+    iVolume->iVolumeTable->PublishConnectionStatus(iVolume);
+   
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::StartInactivityTimer
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::StartInactivityTimer()
+    {
+    if (iInactivityTimer)
+        {
+        DEBUGSTRING(("inactivity timer started (%d us)",
+                     iInactivityTimeout));
+        iInactivityTimer->Cancel();
+        TCallBack callBack(CRsfwFileEngine::InactivityTimerExpired, this);
+        iInactivityTimer->Start(iInactivityTimeout,
+                                iInactivityTimeout,
+                                callBack);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::StopInactivityTimer
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::StopInactivityTimer()
+    {
+    DEBUGSTRING(("CRsfwFileEngine::StopInactivityTimer"));
+    if (iInactivityTimer)
+        {
+        DEBUGSTRING(("inactivity timer stopped"));
+        iInactivityTimer->Cancel();
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::InactivityTimerExpired
+// ----------------------------------------------------------------------------
+//
+TInt CRsfwFileEngine::InactivityTimerExpired(TAny* aArg)
+    {
+    DEBUGSTRING(("CRsfwFileEngine::InactivityTimerExpired"));
+    CRsfwFileEngine* fileEngine = static_cast<CRsfwFileEngine*>(aArg);
+    if (fileEngine->iFileTable->OpenFileCount() == 0) 
+        {
+        fileEngine->StopInactivityTimer();
+        TRAP_IGNORE(fileEngine->DisconnectL());
+        // "Simulate" operation completion (which may result in RFE shutdown)
+        fileEngine->OperationCompleted();
+        }
+    else 
+        {
+        // if there are open files on this volume, just restart the inactivity timer
+        fileEngine->StartInactivityTimer();
+        }
+
+    return 0;
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::HandleRemoteAccessEventL
+// ----------------------------------------------------------------------------
+//
+void CRsfwFileEngine::HandleRemoteAccessEventL(TInt aEventType,
+                                           TInt aEvent,
+                                           TAny* /* aArg */)
+    {
+    DEBUGSTRING(("Handle remote access event: %d/%d in connection state %d",
+                 aEventType,
+                 aEvent,
+                 iConnectionState));
+    switch (aEventType)
+        {
+    case ERsfwRemoteAccessObserverEventConnection:
+        switch (aEvent)
+            {
+        case ERsfwRemoteAccessObserverEventConnectionDisconnected:
+            EnteredConnectionStateL(KMountNotConnected, EFalse);
+            break;
+
+        case ERsfwRemoteAccessObserverEventConnectionWeaklyConnected:
+#if 0
+            // This event does not appear
+            EnteredConnectionStateL(KMountWeaklyConnected, EFalse);
+#endif
+            break;
+
+        case ERsfwRemoteAccessObserverEventConnectionStronglyConnected:
+#if 0
+            // This event does not appear
+            EnteredConnectionStateL(KMountStronglyConnected, EFalse);
+#endif
+            break;
+
+        default:
+            break;
+            }
+        break;
+
+    default:
+        break;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CRsfwFileEngine::PurgeFromCacheL
+// ----------------------------------------------------------------------------
+//
+TInt CRsfwFileEngine::PurgeFromCache(const TDesC& aPath) 
+    {
+    // get the fid of the entry for which the cached data is removed
+    CRsfwFileEntry* targetFid = FetchFep(aPath);
+    if (!targetFid) 
+        {
+        return KErrPathNotFound;
+        }
+    // only directories can be refreshed currently    
+    if (targetFid->Type() != KNodeTypeDir) 
+        {
+        return KErrArgument;
+        }
+    targetFid->SetCached(EFalse);    
+    return KErrNone;
+    }
+                                           
+CRsfwFileEntry* CRsfwFileEngine::FetchFep(const TDesC& aPath) 
+    {
+    DEBUGSTRING16(("CRsfwFileEngine::FetchFep for file %S", &aPath));
+    if (aPath.Length() <= 1)
+        {
+        DEBUGSTRING(("returning rootFep"));
+        return iRootFep;
+        }
+    else 
+        {
+        TInt delimiterPos = aPath.LocateReverse(KPathDelimiter);
+        if (delimiterPos == (aPath.Length() - 1))
+            {
+            // The path ends with a slash,
+            //i.e. this is a directory - continue parsing
+            TPtrC nextdelimiter;
+            nextdelimiter.Set(aPath.Left(delimiterPos));
+            delimiterPos = nextdelimiter.LocateReverse(KPathDelimiter);
+            }
+        TPtrC entry(aPath.Right(aPath.Length() - (delimiterPos + 1)));
+        TPtrC path(aPath.Left(delimiterPos + 1));
+        
+        // strip a trailing backslash if found
+        delimiterPos = entry.LocateReverse(KPathDelimiter);
+        if (delimiterPos == (entry.Length() - 1)) 
+            {
+            TPtrC stripped(entry.Left(entry.Length() - 1));
+            return (FetchFep(path)->FindKidByName(stripped));
+            }
+           else 
+            {
+            return (FetchFep(path)->FindKidByName(entry));
+            }
+        
+        }
+
+    }
+    
+HBufC8* CRsfwFileEngine::GetContentType(TDesC& aName)
+     {
+     TInt err;
+     RApaLsSession lsSession;
+     err = lsSession.Connect();
+     if (err) 
+         {
+         return NULL;
+         }
+         
+     RFs fsSession;
+     err = fsSession.Connect();
+     if (err) 
+         {
+         lsSession.Close();
+         return NULL;
+         }
+     fsSession.ShareProtected();
+     TDataRecognitionResult dataType;
+     RFile theFile;
+     // the mode must mach the mode that is used in the file system plugin
+     // (EFileWrite|EFileShareAny)
+     err = theFile.Open(fsSession, aName, EFileWrite|EFileShareAny);
+     if (err) 
+         {
+         lsSession.Close();
+         fsSession.Close();
+         return NULL;
+         }
+     err = lsSession.RecognizeData(theFile, dataType);
+     lsSession.Close();
+     theFile.Close();
+     fsSession.Close();
+     if (err) 
+         {
+         return NULL;
+         }
+      
+     return dataType.iDataType.Des8().Alloc();
+     }    
+
+ // The purpose of these functions is to give capability info
+ // for the access protocol plugin used.
+ 
+ // Currently this information is hard coded and takes into account webdav and upnp
+ // access modules. New function should be added to the access plugin api to get
+ // this information from the protocol module
+    
+  // whether getting the directory listing also gives reliable file metadata
+TBool CRsfwFileEngine::DirectoryListingContainsFileMetadata() 
+    {
+    _LIT(KUPnP, "upnp");
+    if (iVolume->MountInfo()->iMountConfig.iUri.Left(4) == KUPnP)
+        {
+        return EFalse;
+        }
+    else 
+        {
+        return ETrue;
+        }
+    
+    }
+