--- /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;
+ }
+
+ }
+