--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/userlibandfileserver/fileserver/sfile/sf_request.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,2475 @@
+// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "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:
+// f32\sfile\sf_request.cpp
+//
+//
+
+#include "sf_std.h"
+#include "sf_file_cache.h"
+#ifdef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
+#include "sf_notifier.h"
+#endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
+
+
+TParse dummyP;
+RMessage2 dummyM;
+
+CFsClientMessageRequest* RequestAllocator::iFreeHead;
+CFsClientMessageRequest* RequestAllocator::iCloseHead;
+TInt RequestAllocator::iAllocNum;
+TInt RequestAllocator::iAllocNumOperation;
+TMsgOperation* RequestAllocator::iFreeHeadSupOp;
+
+#if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
+TInt RequestAllocator::iAllocated;
+#endif
+RFastLock RequestAllocator::iCacheLock;
+
+void RequestAllocator::Initialise()
+ {
+ iFreeHead=NULL;
+ iCloseHead=NULL;
+ iAllocNum=0;
+#if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
+ iAllocated=0;
+#endif
+ iAllocNumOperation=0;
+ iFreeHeadSupOp=NULL;
+ }
+
+TInt RequestAllocator::AllocRequest(TInt aNum)
+//
+// Allocates a group of request objects
+//
+ {
+ TInt i;
+ if(iAllocNum < KMaxRequestAllocated)
+ {
+ __CACHE_PRINT(_L("RequestAllocator::AllocRequest() Not reached the limit"));
+ CFsClientMessageRequest* list;
+ CFsClientMessageRequest* start;
+ list = new CFsClientMessageRequest[KAllocReqBlock];
+ start = list;
+ if(!list)
+ return KErrNoMemory;
+
+ // Make sure the constructors are called for every element in the array
+ // - some compilers don't do this
+ for(TInt j=0; j<KAllocReqBlock; j++)
+ {
+ CFsClientMessageRequest* request = &list[j];
+ new(request) CFsClientMessageRequest();
+ }
+
+ iAllocNum += KAllocReqBlock;
+ CFsClientMessageRequest* last;
+ for(i=1;i<KAllocReqBlock;i++)
+ {
+ last = list;
+ list++;
+ last->iNext = list;
+ }
+ list->iNext = iFreeHead;
+ iFreeHead = start;
+ return KErrNone;
+ }
+ else
+ {
+ __CACHE_PRINT1(_L("RequestAllocator::AllocRequest() Limit exceeded Count = %d"),aNum);
+ CFsClientMessageRequest* request;
+ for(i=0;i<aNum;i++)
+ {
+ request=new CFsClientMessageRequest;
+ if(!request)
+ return KErrNoMemory;
+#if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
+ iAllocated++;
+#endif
+ request->SetAllocated();
+ request->iNext=iFreeHead;
+ iFreeHead=request;
+ }
+ return KErrNone;
+ }
+ }
+
+void RequestAllocator::FreeRequest(CFsClientMessageRequest* aRequest)
+//
+//free request
+//
+ {
+ __CACHE_PRINT1(_L("PLUGIN: RequestAllocator::FreeRequest for %x"), aRequest);
+ if(aRequest->IsAllocated())
+ {
+ __CACHE_PRINT(_L("RequestAllocator::FreeRequest() Allocated request"));
+ delete(aRequest);
+#if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
+ iAllocated--;
+#endif
+ return;
+ }
+
+ __CACHE_PRINT(_L("RequestAllocator::FreeRequest() returning to free list"));
+ iCacheLock.Wait();
+ aRequest->iNext = iFreeHead;
+ iFreeHead=aRequest;
+ aRequest->SetSubstedDrive(NULL);
+ iCacheLock.Signal();
+ }
+
+void RequestAllocator::OpenSubFailed(CSessionFs* aSession)
+//
+// Move requst from closed list to free list
+//
+ {
+ __ASSERT_DEBUG(iCloseHead!=NULL,Fault(ERequestAllocatorOpenSubFailed)); // On arriving here Close Queue is supposed to be empty
+ __ASSERT_ALWAYS(aSession!=NULL,Fault(ERequestAllocatorOpenSubFailed));
+ if (iCloseHead==NULL)
+ {
+ return;
+ }
+ iCacheLock.Wait();
+ CFsClientMessageRequest* rp = iCloseHead;
+ iCloseHead = rp->iNext;
+
+ // dec the number of closed requests owned by this session
+ aSession->CloseRequestCountDec();
+
+ rp->iNext = NULL;
+ if(rp->IsAllocated())
+ {
+ __CACHE_PRINT(_L("RequestAllocator::OpenSubFailed() Allocated request"));
+ delete(rp);
+#if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
+ iAllocated--;
+#endif
+ }
+ else
+ {
+ __CACHE_PRINT(_L("RequestAllocator::OpenSubFailed()"));
+ if(iFreeHead)
+ {
+ rp->iNext = iFreeHead;
+ }
+ else
+ {
+ rp->iNext = NULL;
+ }
+
+ iFreeHead = rp;
+ }
+ iCacheLock.Signal();
+ }
+
+TInt RequestAllocator::GetMessageRequest(const TOperation& aOperation,const RMessage2& aMessage,CFsClientMessageRequest* &aRequest)
+//
+// tries to get a pre allocated message from the cache. Failing that allocates one indivisualy
+//
+ {
+ if(aOperation.IsOpenSubSess())
+ {
+ __CACHE_PRINT(_L("++RequestAllocator::GetMessageRequest() Open sub-sess"));
+ iCacheLock.Wait();
+ if(iFreeHead == NULL || iFreeHead->iNext == NULL)
+ {
+ if(AllocRequest(2)!= KErrNone)
+ {
+ iCacheLock.Signal();
+ return KErrNoMemory;
+ }
+ }
+ aRequest= iFreeHead; //get our request from free head
+ iFreeHead = iFreeHead->iNext->iNext; //set next but one as new free head read for next
+
+ aRequest->iNext->iNext = NULL; //seperate our request and close from free list
+ CFsClientMessageRequest* CRp = aRequest->iNext;
+ aRequest->iNext = NULL;
+ if(iCloseHead)
+ {
+ CRp->iNext = iCloseHead; //set second one as a reserved (tail) close request
+ iCloseHead = CRp;
+ }
+ else
+ iCloseHead = CRp;
+
+ ((CSessionFs*) aMessage.Session())->CloseRequestCountInc();
+ }
+ else if(aOperation.IsCloseSubSess())
+ {
+ __CACHE_PRINT(_L("++RequestAllocator::GetMessageRequest() Close sub-sess"));
+
+ CFsObject* pO = SessionObjectFromHandle(aMessage.Int3(),0,reinterpret_cast<CSessionFs*>(aMessage.Session()));
+ if(!pO)
+ return KErrBadHandle;
+
+ CObjPromotion* pm = (CObjPromotion*)pO;
+ TInt function = aMessage.Function();
+ switch(function & KIpcFunctionMask)
+ {
+ case EFsFormatSubClose:
+ {
+ if(pm->UniqueID() != Formats->UniqueID())
+ {
+ return KErrBadHandle;
+ }
+ break;
+ }
+ case EFsDirSubClose:
+ {
+ if(pm->UniqueID() != Dirs->UniqueID())
+ {
+ return KErrBadHandle;
+ }
+ break;
+ }
+ case EFsFileSubClose:
+ {
+ if(pm->UniqueID() != FileShares->UniqueID())
+ {
+ return KErrBadHandle;
+ }
+ break;
+ }
+ case EFsRawSubClose:
+ {
+ if(pm->UniqueID() != RawDisks->UniqueID())
+ {
+ return KErrBadHandle;
+ }
+ break;
+ }
+ case EFsPluginSubClose:
+ {
+ if(pm->UniqueID() != FsPluginManager::iPluginConns->UniqueID())
+ {
+ return KErrBadHandle;
+ }
+ break;
+ }
+#ifdef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
+ case EFsNotificationSubClose:
+ {
+ if(pm->UniqueID() != FsNotificationManager::iNotifyRequests->UniqueID())
+ {
+ return KErrBadHandle;
+ }
+ break;
+ }
+#endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
+ default:
+ Fault(ECloseSubBadMessage);
+ }
+
+ iCacheLock.Wait();
+ aRequest = iCloseHead;
+ iCloseHead = aRequest->iNext;
+ ((CSessionFs*) aMessage.Session())->CloseRequestCountDec();
+ aRequest->iNext = NULL;
+
+ if((function & KIpcFunctionMask)!= EFsPluginSubClose &&
+ (function & KIpcFunctionMask)!= EFsNotificationSubClose)
+ {
+ aRequest->SetDrive(&TheDrives[((CFsDispatchObject*)pO)->DriveNumber()]);
+ }
+
+ aRequest->SetScratchValue((TUint)pO);
+ }
+ else
+ {
+ __CACHE_PRINT(_L("++RequestAllocator::GetMessageRequest() "));
+ iCacheLock.Wait();
+ if(!iFreeHead)
+ {
+ if(AllocRequest(1) != KErrNone)
+ {
+ iCacheLock.Signal();
+ return KErrNoMemory;
+ }
+ }
+ aRequest = iFreeHead;
+ iFreeHead = aRequest->iNext;
+ aRequest->iNext= NULL;
+ }
+
+ aRequest->Init();
+
+ iCacheLock.Signal();
+
+ // pre-allocate any TParse objects needed by this request
+ if (aRequest->AllocParseObjects(aOperation) != KErrNone)
+ {
+ aRequest->Free();
+ return KErrNoMemory;
+ }
+
+ __CACHE_PRINT1(_L("--RequestAllocator::GetMessageRequest() allocated %08x"), aRequest);
+
+ return KErrNone;
+ }
+
+
+#if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
+TInt RequestAllocator::CloseCount()
+ {TInt count=0;
+ CFsClientMessageRequest* list=iCloseHead;
+ while(list!=NULL)
+ {
+ count++;
+ list=list->iNext;
+ }
+ return(count);
+ }
+TInt RequestAllocator::FreeCount()
+ {
+ TInt count=0;
+ CFsClientMessageRequest* list=iFreeHead;
+ while(list!=NULL)
+ {
+ count++;
+ list=list->iNext;
+ }
+ return(count);}
+#endif
+
+TInt RequestAllocator::AllocOperation()
+//
+// Allocates a group of TMsgOperation objects
+//
+// Must be called with iCacheLock held
+ {
+ TInt i;
+ if(iAllocNumOperation < KMaxOperationAllocated)
+ {
+ __CACHE_PRINT(_L("RequestAllocator::AllocOperation() Not reached the limit"));
+ TMsgOperation* list;
+ TMsgOperation* start;
+ list = new TMsgOperation[KAllocReqBlock];
+ start = list;
+ if(!list)
+ return KErrNoMemory;
+
+ for(TInt j=0; j<KAllocReqBlock; j++)
+ {
+ TMsgOperation* request = &list[j];
+ request->iIsAllocated = EFalse;
+ }
+
+ iAllocNumOperation += KAllocReqBlock;
+ TMsgOperation* last;
+ for(i=1;i<KAllocReqBlock;i++)
+ {
+ last = list;
+ list++;
+ last->iNext = list;
+ }
+ list->iNext = iFreeHeadSupOp;
+ iFreeHeadSupOp = start;
+ return KErrNone;
+ }
+ else
+ {
+ __CACHE_PRINT(_L("RequestAllocator::AllocOperation() Limit exceeded"));
+ TMsgOperation* request;
+
+ request=new TMsgOperation;
+ if(!request)
+ return KErrNoMemory;
+#if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
+ iAllocated++;
+#endif
+ request->iIsAllocated = ETrue;
+ request->iNext=iFreeHeadSupOp;
+ iFreeHeadSupOp=request;
+
+ return KErrNone;
+ }
+ }
+TInt RequestAllocator::GetOperation(TMsgOperation* &aOperation)
+//
+// tries to get a pre allocated subop from the cache. Failing that allocates one individualy
+//
+ {
+
+ __CACHE_PRINT(_L("RequestAllocator::GetOperation() "));
+ iCacheLock.Wait();
+ if(!iFreeHeadSupOp)
+ {
+ if(AllocOperation() != KErrNone)
+ {
+ iCacheLock.Signal();
+ return KErrNoMemory;
+ }
+ }
+ aOperation = iFreeHeadSupOp;
+ iFreeHeadSupOp = aOperation->iNext;
+ aOperation->iNext = aOperation->iPrev = NULL;
+
+ iCacheLock.Signal();
+ return KErrNone;
+ }
+
+void RequestAllocator::FreeOperation(TMsgOperation* aOperation)
+//
+// free Operation
+//
+ {
+ if(aOperation->iIsAllocated)
+ {
+ __CACHE_PRINT(_L("RequestAllocator::FreeOperation() Allocated subop"));
+ delete(aOperation);
+#if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
+ iAllocated--;
+#endif
+ return;
+ }
+
+ __CACHE_PRINT(_L("RequestAllocator::FreeOperation() returning to free list"));
+ iCacheLock.Wait();
+ aOperation->iNext = iFreeHeadSupOp; // NB backward link only used when request in in use
+ iFreeHeadSupOp = aOperation;
+
+ iCacheLock.Signal();
+ }
+
+
+CFsRequest::CFsRequest()
+//
+//
+//
+ : iOperation(NULL),iDriveNumber(KDriveInvalid)
+ {}
+
+CFsRequest::~CFsRequest()
+//
+//
+//
+ {}
+
+void CFsRequest::Set(const TOperation& aOperation,CSessionFs* aSession)
+//
+//
+//
+ {
+
+ SetState(EReqStateInitialise);
+
+ iOperation = const_cast<TOperation*>(&aOperation);
+ iSession = aSession;
+ iIsCompleted = aOperation.IsCompleted();
+ iError = KErrNone;
+ iDriveNumber = KDriveInvalid;
+ iCurrentPlugin = NULL;
+ iOwnerPlugin = NULL;
+ iDirectToDrive = EFalse;
+ iClientThreadId= 0;
+ iFlags &= ~(EFreeChanged | EPostInterceptEnabled | EPostOperation | EFsObjectOpen);
+ iScratchValue = 0;
+ }
+
+void CFsRequest::Set(CSessionFs* aSession)
+//
+//
+//
+ {
+ __ASSERT_DEBUG(iOperation,Fault(EBaseRequestSet1));
+
+ SetState(EReqStateInitialise);
+
+ iSession = aSession;
+ iIsCompleted = iOperation->IsCompleted();
+ iError = KErrNone;
+ iDriveNumber = KDriveInvalid;
+ iCurrentPlugin = NULL;
+ iOwnerPlugin = NULL;
+ iDirectToDrive = EFalse;
+ iClientThreadId= 0;
+ iFlags &= ~(EFreeChanged | EPostInterceptEnabled | EPostOperation | EFsObjectOpen);
+ iScratchValue = 0;
+ }
+
+
+TParse& CFsRequest::Src()
+//
+//
+//
+ {
+ Fault(EBaseRequestSrc);
+ return(dummyP);
+ }
+
+TParse& CFsRequest::Dest()
+//
+//
+//
+ {
+ Fault(EBaseRequestDest);
+ return(dummyP);
+ }
+
+TDrive* CFsRequest::Drive()
+//
+//
+//
+ {
+ Fault(EBaseRequestDrive);
+ return(NULL);
+ }
+
+TDrive* CFsRequest::SubstedDrive()
+//
+//
+//
+ {
+ Fault(EBaseRequestSubstedDrive);
+ return(NULL);
+ }
+
+void CFsRequest::SetDrive(TDrive* /*aDrive*/)
+//
+//
+//
+ {
+ Fault(EBaseRequestSetDrive);
+ }
+
+void CFsRequest::SetSubstedDrive(TDrive* /*aDrive*/)
+//
+//
+//
+ {
+ Fault(EBaseRequestSetSubstedDrive);
+ }
+
+TInt CFsRequest::GetSlot(TFsPluginRequest::TF32ArgType aType)
+ {
+ if(iOperation->Arg(0) == aType) return 0;
+ if(iOperation->Arg(1) == aType) return 1;
+ if(iOperation->Arg(2) == aType) return 2;
+ if(iOperation->Arg(3) == aType) return 3;
+
+ return(-1);
+ }
+
+
+TBool CFsMessageRequest::IsNotifierSpecific() const
+ {
+#ifndef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
+ return EFalse;
+#else
+ TInt function = iOperation->iFunction;
+ return( function == EFsNotificationAdd ||
+ function == EFsNotificationBuffer ||
+ function == EFsNotificationCancel ||
+ function == EFsNotificationOpen ||
+ function == EFsNotificationRemove ||
+ function == EFsNotificationRequest ||
+ function == EFsNotificationSubClose);
+#endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
+ }
+
+
+TBool CFsMessageRequest::IsNotifierSupported() const
+ {
+#ifndef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
+ return EFalse;
+#else
+ TInt function = iOperation->iFunction;
+ return( function == EFsDelete ||
+ function == EFsRmDir ||
+ function == EFsMkDir ||
+ function == EFsFormatNext ||
+ function == EFsFileCreate ||
+ function == EFsFileReplace ||
+ function == EFsFileRename ||
+ function == EFsRename ||
+ function == EFsReplace ||
+ function == EFsSetDriveName ||
+ function == EFsSetVolume ||
+ function == EFsSetEntry ||
+ function == EFsFileSetAtt ||
+ function == EFsFileSet ||
+ function == EFsMountFileSystem ||
+ function == EFsDismountFileSystem ||
+ function == EFsFileSetSize ||
+ function == EFsFileWrite ||
+ function == EFsFileWriteDirty ||
+ function == EFsRawDiskWrite ||
+ function == EFsMountFileSystemScan);
+#endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
+ }
+
+
+TInt CFsRequest::Read(TFsPluginRequest::TF32ArgType aType, TInt& aVal)
+ {
+ if(iOperation->Arg(0) == aType) { aVal = Message().Int0(); return KErrNone; }
+ if(iOperation->Arg(1) == aType) { aVal = Message().Int1(); return KErrNone; }
+ if(iOperation->Arg(2) == aType) { aVal = Message().Int2(); return KErrNone; }
+ if(iOperation->Arg(3) == aType) { aVal = Message().Int3(); return KErrNone; }
+
+ return KErrNotSupported;
+ }
+
+
+TInt CFsRequest::Read(TFsPluginRequest::TF32ArgType aType, TUint& aVal)
+ {
+ if(iOperation->Arg(0) == aType) { aVal = (TUint)Message().Int0(); return KErrNone; }
+ if(iOperation->Arg(1) == aType) { aVal = (TUint)Message().Int1(); return KErrNone; }
+ if(iOperation->Arg(2) == aType) { aVal = (TUint)Message().Int2(); return KErrNone; }
+ if(iOperation->Arg(3) == aType) { aVal = (TUint)Message().Int3(); return KErrNone; }
+
+ return KErrNotSupported;
+ }
+
+TInt CFsRequest::Read(TFsPluginRequest::TF32ArgType aType, TInt64& aVal)
+ {
+ TPckg<TInt64> pkVal(aVal);
+ // EFsFileLock, EFsFileUnLock, EFsFileSeek and EFsFileSetSize need special treatment
+ if(iOperation->Arg(0) == aType)
+ {
+ if((iOperation->Function()==EFsFileLock) ||
+ (iOperation->Function()==EFsFileUnLock) )
+ {
+ if(IsDescData(KMsgPtr0))
+ Read(KMsgPtr0,pkVal);
+ else
+ aVal = MAKE_TINT64(0, Message().Int0()); // Position is unsigned value
+ return KErrNone;
+ }
+
+ if((iOperation->Function()==EFsFileSeek) || // Seek offset (input paramater)
+ (iOperation->Function()==EFsFileSize) || // Size (output paramater)
+ (iOperation->Function()==EFsFileSetSize) ) // Size to be set (input paramater)
+ {
+ if(IsDescData(KMsgPtr0))
+ Read(KMsgPtr0,pkVal);
+ else
+ aVal = Message().Int0(); // Seek offset / Size is signed value
+ return KErrNone;
+ }
+
+ aVal = Message().Int0();
+ return KErrNone;
+ }
+
+ // EFsFileLock and EFsFileUnLock need special treatment
+ if(iOperation->Arg(1) == aType)
+ {
+ if((iOperation->Function()==EFsFileLock) ||
+ (iOperation->Function()==EFsFileUnLock) )
+ {
+ if(IsDescData(KMsgPtr1))
+ Read(KMsgPtr1,pkVal);
+ else
+ aVal = MAKE_TINT64(0, Message().Int1()); // Length is unsigned value
+ return KErrNone;
+ }
+
+ aVal = Message().Int1();
+ return KErrNone;
+ }
+
+ // EFsFileRead, EFsFileWrite, EFsFileSeek and EFsReadFileSection need special treatment
+ if(iOperation->Arg(2) == aType)
+ {
+ if((iOperation->Function()==EFsFileRead) ||
+ (iOperation->Function()==EFsFileWrite) )
+ {
+ if(IsDescData(KMsgPtr2))
+ Read(KMsgPtr2,pkVal);
+ else
+ {
+ if(Message().Int2() == (TInt)I64LOW(KCurrentPosition64))
+ aVal = KCurrentPosition64; // Position is KCurrentPosition64 (-1)
+ else
+ aVal = MAKE_TINT64(0,Message().Int2()); // Position is unsigned value
+ }
+ return KErrNone;
+ }
+
+ if(iOperation->Function()==EFsFileSeek)
+ {
+ if(IsDescData(KMsgPtr2))
+ Read(KMsgPtr2,pkVal);
+ else
+ aVal = Message().Int2(); // New position is signed value
+ return KErrNone;
+ }
+
+ if(iOperation->Function()==EFsReadFileSection)
+ {
+ if(IsDescData(KMsgPtr2))
+ Read(KMsgPtr2,pkVal);
+ else
+ aVal = MAKE_TINT64(0,Message().Int2()); // Position is unsigned value
+ return KErrNone;
+ }
+
+ aVal = Message().Int2();
+ return KErrNone;
+ }
+
+ if(iOperation->Arg(3) == aType)
+ {
+ aVal = Message().Int3();
+ return KErrNone;
+ }
+
+ return KErrNotSupported;
+ }
+
+void CFsRequest::SetAndOpenScratchValue(const TInt64& aValue)
+ {
+ if (IsFsObjectOpen())
+ {
+ ((CFsDispatchObject*) I64LOW(iScratchValue))->Close();
+ SetFsObjectOpen(EFalse);
+ }
+ if (I64LOW(aValue) && iOperation && (iOperation->iFlags & EFileShare))
+ {
+ ((CFsDispatchObject*) I64LOW(aValue))->Open();
+ SetFsObjectOpen(ETrue);
+ }
+ iScratchValue = aValue;
+ }
+
+
+TInt CFsRequest::Read(TFsPluginRequest::TF32ArgType aType, TDes8& aDes, TInt aOffset)
+ {
+ TInt slot = GetSlot(aType);
+ if(slot >= 0)
+ return Read(slot, aDes, aOffset);
+ return KErrNotSupported;
+ }
+
+
+TInt CFsRequest::Read(TFsPluginRequest::TF32ArgType aType, TDes16& aDes, TInt aOffset)
+ {
+ TInt slot = GetSlot(aType);
+ if(slot >= 0)
+ return Read(slot, aDes, aOffset);
+ return KErrNotSupported;
+ }
+
+
+TInt CFsRequest::Write(TFsPluginRequest::TF32ArgType aType, const TDesC8& aDes, TInt aOffset)
+ {
+ TInt slot = GetSlot(aType);
+ if(slot >= 0)
+ return Write(slot, aDes, aOffset);
+ return KErrNotSupported;
+ }
+
+
+TInt CFsRequest::Write(TFsPluginRequest::TF32ArgType aType, const TDesC16& aDes, TInt aOffset)
+ {
+ TInt slot = GetSlot(aType);
+ if(slot >= 0)
+ return Write(slot, aDes, aOffset);
+ return KErrNotSupported;
+ }
+
+
+TInt CFsRequest::Read(const TInt aMsgPtr,TDes8 &aDes)
+ {
+ if (Message().Handle() == KLocalMessageHandle)
+ {
+ TDesC8* pDes = (TDesC8*) ((const RLocalMessage*) &Message())->Arg(aMsgPtr);
+ if (aDes.MaxLength() < pDes->Length())
+ return KErrTooBig;
+ aDes.Copy(*pDes);
+ return KErrNone;
+ }
+
+ return Message().Read(aMsgPtr,aDes,0);
+ }
+
+
+TInt CFsRequest::Read(const TInt aMsgPtr,TDes8 &aDes,TInt anOffset)
+ {
+ if (Message().Handle() == KLocalMessageHandle)
+ {
+ TDesC8* pDes = (TDesC8*) ((const RLocalMessage*) &Message())->Arg(aMsgPtr);
+ if (aDes.MaxLength() < pDes->Length() + anOffset)
+ return KErrTooBig;
+ aDes.SetLength(pDes->Length() + anOffset);
+ aDes.MidTPtr(anOffset).Copy(*pDes);
+ return KErrNone;
+ }
+
+ return Message().Read(aMsgPtr,aDes,anOffset);
+ }
+
+
+TInt CFsRequest::Read(const TInt aMsgPtr,TDes16 &aDes)
+ {
+ if (Message().Handle() == KLocalMessageHandle)
+ {
+ TDesC16* pDes = (TDesC16*) ((const RLocalMessage*) &Message())->Arg(aMsgPtr);
+ if (aDes.MaxLength() < pDes->Length())
+ return KErrTooBig;
+ aDes.Copy(*pDes);
+ return KErrNone;
+ }
+
+ return Message().Read(aMsgPtr,aDes,0);
+ }
+
+
+TInt CFsRequest::Read(const TInt aMsgPtr,TDes16 &aDes,TInt anOffset)
+ {
+ if (Message().Handle() == KLocalMessageHandle)
+ {
+ TDesC16* pDes = (TDesC16*) ((const RLocalMessage*) &Message())->Arg(aMsgPtr);
+ if (aDes.MaxLength() < pDes->Length() + anOffset)
+ return KErrTooBig;
+ aDes.SetLength(pDes->Length() + anOffset);
+ aDes.MidTPtr(anOffset).Copy(*pDes);
+ return KErrNone;
+ }
+
+ return Message().Read(aMsgPtr,aDes,anOffset);
+ }
+
+
+TInt CFsRequest::Write(const TInt aMsgNum,const TDesC8 &aDes)
+ {
+ if (Message().Handle() == KLocalMessageHandle)
+ {
+ TDes8* pDes = (TDes8*) ((const RLocalMessage*) &Message())->Arg(aMsgNum);
+ if (pDes->MaxLength() < aDes.Length())
+ return KErrTooBig;
+ pDes->Copy(aDes);
+ return KErrNone;
+ }
+
+ return Message().Write(aMsgNum,aDes,0);
+ }
+
+
+TInt CFsRequest::Write(const TInt aMsgNum,const TDesC8 &aDes,TInt anOffset)
+ {
+ if (Message().Handle() == KLocalMessageHandle)
+ {
+ TDes8* pDes = (TDes8*) ((const RLocalMessage*) &Message())->Arg(aMsgNum);
+ if (pDes->MaxLength() < aDes.Length() + anOffset)
+ return KErrTooBig;
+ pDes->SetLength(aDes.Length() + anOffset);
+ pDes->MidTPtr(anOffset).Copy(aDes);
+ return KErrNone;
+ }
+
+ return Message().Write(aMsgNum,aDes,anOffset);
+ }
+
+
+TInt CFsRequest::Write(const TInt aMsgNum,const TDesC16 &aDes)
+ {
+ if (Message().Handle() == KLocalMessageHandle)
+ {
+ TDes16* pDes = (TDes16*) ((const RLocalMessage*) &Message())->Arg(aMsgNum);
+ if (pDes->MaxLength() < aDes.Length())
+ return KErrTooBig;
+ pDes->Copy(aDes);
+ return KErrNone;
+ }
+
+ return Message().Write(aMsgNum,aDes,0);
+ }
+
+
+TInt CFsRequest::Write(const TInt aMsgNum,const TDesC16 &aDes,TInt anOffset)
+ {
+ if (Message().Handle() == KLocalMessageHandle)
+ {
+ TDes16* pDes = (TDes16*) ((const RLocalMessage*) &Message())->Arg(aMsgNum);
+ if (pDes->MaxLength() < aDes.Length() + anOffset)
+ return KErrTooBig;
+ pDes->SetLength(aDes.Length() + anOffset);
+ pDes->MidTPtr(anOffset).Copy(aDes);
+ return KErrNone;
+ }
+
+ return Message().Write(aMsgNum,aDes,anOffset);
+ }
+
+
+void CFsRequest::ReadL(const TInt aMsgPtr,TDes8 &aDes)
+ { User::LeaveIfError(Read(aMsgPtr,aDes)); }
+
+void CFsRequest::ReadL(const TInt aMsgPtr,TDes8 &aDes,TInt anOffset)
+ { User::LeaveIfError(Read(aMsgPtr,aDes,anOffset)); }
+
+void CFsRequest::ReadL(const TInt aMsgPtr,TDes16 &aDes)
+ { User::LeaveIfError(Read(aMsgPtr,aDes)); }
+
+void CFsRequest::ReadL(const TInt aMsgPtr,TDes16 &aDes,TInt anOffset)
+ { User::LeaveIfError(Read(aMsgPtr,aDes,anOffset)); }
+
+void CFsRequest::WriteL(const TInt aMsgNum,const TDesC8 &aDes)
+ { User::LeaveIfError(Write(aMsgNum,aDes)); }
+
+void CFsRequest::WriteL(const TInt aMsgNum,const TDesC8 &aDes,TInt anOffset)
+ { User::LeaveIfError(Write(aMsgNum,aDes,anOffset)); }
+
+void CFsRequest::WriteL(const TInt aMsgNum,const TDesC16 &aDes)
+ { User::LeaveIfError(Write(aMsgNum,aDes)); }
+
+void CFsRequest::WriteL(const TInt aMsgNum,const TDesC16 &aDes,TInt anOffset)
+ { User::LeaveIfError(Write(aMsgNum,aDes,anOffset)); }
+
+
+/**
+ @param aMsgNum message argument index
+ @return client side descriptor length
+*/
+TInt CFsRequest::GetDesLength(const TInt aMsgNum)
+ {
+ if (Message().Handle() == KLocalMessageHandle)
+ {
+ TDes8* pDes = (TDes8*) ((const RLocalMessage*) &Message())->Arg(aMsgNum);
+ return pDes->Length();
+ }
+ else
+ {
+ return Message().GetDesLength(aMsgNum);
+ }
+ }
+
+const RMessage2& CFsRequest::Message()
+//
+//
+//
+ {
+ Fault(EBaseRequestMessage);
+ return(dummyM);
+ }
+
+
+
+void CFsMessageRequest::Set(const RMessage2& aMessage,CSessionFs* aSession)
+//
+// For reuseable request
+//
+ {
+ iMessage=aMessage;
+ iDrive=NULL;
+ iSubstedDrive=NULL;
+ CFsRequest::Set(aSession);
+ SetFreeChanged(EFalse);
+ EnablePostIntercept(ETrue);
+ }
+
+
+void CFsMessageRequest::Set(const RMessage2& aMessage,const TOperation& aOperation,CSessionFs* aSession)
+//
+//
+//
+ {
+ iCurrentPlugin=NULL;
+ iMessage=aMessage;
+ iDrive=NULL;
+ iSubstedDrive=NULL;
+ CFsRequest::Set(aOperation,aSession);
+ SetFreeChanged(EFalse);
+ EnablePostIntercept(ETrue);
+ }
+
+void CFsMessageRequest::Set(const TOperation& aOperation)
+ {
+ iOperation=const_cast<TOperation*>(&aOperation);
+ }
+
+void CFsMessageRequest::Process()
+//
+// Process the request - (passing to a plugin or a drive thread)
+//
+ {
+ __THRD_PRINT3(_L("CFsMessageRequest::Process() req %08x state %d plugin 0x%x"), this, iReqState, iCurrentPlugin);
+
+ // initialise request - if not initialised already
+ if (iReqState == EReqStateInitialise)
+ {
+ TInt r = DoInitialise();
+ if (r == EReqActionComplete)
+ {
+ return;
+ }
+ else if (r == EReqActionBusy) // request postponed ?
+ {
+ SetState(EReqStateInitialise);
+ Dispatch(EFalse);
+ return;
+ }
+ else if (r == KErrNone && iCurrentPlugin) // dispatch to plugin thread ?
+ {
+ Dispatch(EFalse);
+ return;
+ }
+ }
+
+ if(iCurrentPlugin)
+ {
+ if (IsPostOperation())
+ {
+ ProcessPostOperation();
+ return;
+ }
+
+ if(!IsPluginSpecific())
+ {
+ ProcessPreOperation();
+ return;
+ }
+ }
+
+
+ // Is there a PostInitialise function ?
+ if (iReqState == EReqStatePostInitialise)
+ {
+ TInt r = PostInitialise();
+ if (r == EReqActionComplete)
+ {
+ return;
+ }
+ else if (r == EReqActionBusy) // request postponed ?
+ {
+ SetState(EReqStatePostInitialise);
+ Dispatch(EFalse);
+ return;
+ }
+ }
+
+ ProcessDriveOperation();
+ }
+
+void CFsMessageRequest::ProcessPostOperation()
+//
+// Process the message in post operation mode (handled by the current plugin)
+//
+ {
+ TInt err = KErrNone;
+ if(!iCurrentPlugin->IsPluginThread(*this))
+ {
+ // The request hasn't come from this plugin so it's safe to dispatch
+ TFsPluginRequest request(this);
+ TRAPD(leaveValue, err = iCurrentPlugin->DoRequestL(request));
+ if(leaveValue != KErrNone)
+ {
+ Panic(KFsClient,leaveValue);
+ if(iOperation->IsOpenSubSess())
+ RequestAllocator::OpenSubFailed(Session());
+ Free();
+ return;
+ }
+
+ if(!IsExpectedResult(err))
+ {
+ Complete(err);
+ return;
+ }
+ }
+
+ // Find the previous plugin in the chain and dispatch
+ // - If no more plugins are interested in this message, then complete
+ FsPluginManager::PrevPlugin(iCurrentPlugin, this, ETrue);
+ if(iCurrentPlugin == NULL)
+ {
+ Complete(GetError());
+ return;
+ }
+
+ Dispatch();
+ return;
+ }
+
+
+void CFsMessageRequest::ProcessPreOperation()
+//
+// Process the message in pre operation mode (handled by the current plugin)
+//
+ {
+ TInt err = KErrNone;
+ if(!iCurrentPlugin->IsPluginThread(*this))
+ {
+ // The request hasn't come from this plugin so it's safe to dispatch
+ TFsPluginRequest request(this);
+ TRAPD(leaveValue, err = iCurrentPlugin->DoRequestL(request));
+ __PLUGIN_PRINT1(_L("PLUGIN: CFsMessageRequest:: %x processed by plugin"), this);
+
+ if((iOperation->Function() == EFsDismountPlugin) && (err != KErrPermissionDenied))
+ {
+ TRAP(leaveValue, err = iOperation->DoRequestL(this));
+ }
+
+ if(leaveValue != KErrNone)
+ {
+ Panic(KFsClient,leaveValue);
+ if(iOperation->IsOpenSubSess()) //this should be close subsession
+ RequestAllocator::OpenSubFailed(Session()); //need a close subsession fail
+ Free();
+ return;
+ }
+ }
+
+ if(err == KErrNone)
+ {
+ // Find the next plugin in the chain and dispatch
+ // - If no more plugins are interested in this message,
+ // then Dispatch() will process the request in drive/main thread context.
+ FsPluginManager::NextPlugin(iCurrentPlugin, this,(TBool)ETrue);
+ if(iCurrentPlugin && IsPostOperation())
+ SetPostOperation(EFalse);
+ Dispatch();
+ return;
+ }
+ // KErrCompletion may be returned by the plugin to
+ // indicate that it has process the message itself (do post-intercept)
+ else if (err == KErrCompletion)
+ {
+ // Find the previous plugin in the chain and dispatch
+ // - If no more plugins are interested in this message, then complete
+ FsPluginManager::PrevPlugin(iCurrentPlugin, this,(TBool)ETrue);
+ if(iCurrentPlugin != NULL)
+ {
+ SetPostOperation(ETrue);
+ err = KErrNone;
+ Dispatch();
+ return;
+ }
+ else
+ {
+ err = KErrNone;
+ }
+ }
+
+ Complete(err);
+ return;
+ }
+
+
+void CFsMessageRequest::ProcessDriveOperation()
+//
+// Process the message in drive (or main thread) context
+//
+ {
+
+ // A new request is to be processed - kick off the inactivity/finalisation timer...
+ FsThreadManager::StartFinalisationTimer(iDriveNumber);
+
+ TInt err = KErrNone;
+
+ TRAPD(leaveValue, err = iOperation->DoRequestL(this));
+
+ // Cancel hung state if a request from the drive thread has finished
+ FsThreadManager::SetDriveHung(DriveNumber(), EFalse);
+
+ if(leaveValue != KErrNone)
+ {
+ Panic(KFsClient,leaveValue);
+ if(iOperation->IsOpenSubSess())
+ RequestAllocator::OpenSubFailed(Session());
+ Free();
+ return;
+ }
+
+ // request postponed ? (e.g. if a page used by file cache is busy,
+ // or because of fair scheduling).
+ if (err == EReqActionBusy)
+ {
+ Dispatch();
+ return;
+ }
+
+ iLastError = err;
+
+ if(!IsExpectedResult(err) || IsPluginSpecific())
+ {
+ // no need to call DoNotify here since that requires err==KErrNone
+ Complete(err);
+ return;
+ }
+
+ SetError(err);
+
+
+ // Start issuing the post-operation requests starting from the bottom of the chain
+ iCurrentPlugin = NULL;
+ if (PostInterceptEnabled())
+ {
+ FsPluginManager::PrevPlugin(iCurrentPlugin, this,(TBool)ETrue);
+ if(iCurrentPlugin && !iCurrentPlugin->IsPluginThread(*this))
+ {
+ SetPostOperation(ETrue);
+ if (DispatchToPlugin())
+ return;
+ }
+ }
+
+ Complete(GetError());
+ return;
+ }
+
+void CFsMessageRequest::Complete(TInt aError)
+//
+//
+//
+ {
+ __THRD_PRINT2(_L("----- CFsMessageRequest::Complete() req %08x with %d"), this, aError);
+
+ if (aError==KErrNoMemory)
+ {
+ if (iDrive) // Not all message requests are associated with a drive!
+ {
+ TDriveInfo di;
+ iDrive->DriveInfo(di);
+ if (di.iType == EMediaRam)
+ aError = KErrNoMemory;
+ }
+ }
+ if(aError!=KErrNone)
+ {
+ if(iOperation->IsOpenSubSess())
+ RequestAllocator::OpenSubFailed(Session());
+ }
+
+ iLastError = aError;
+
+ // Call the current MessageOp's completion routine - if this returns EReqActionComplete,
+ // then pop the request and call the next MessageOps's completion routine.
+ // Do this until there are no more MessageOp's on the stack.
+ //
+ // Completion return codes:
+ // EReqActionOwnedByPlugin: DON'T dispatch message again, DON'T complete message
+ // EReqActionComplete: DON'T dispatch message again, DO complete message
+ // EReqActionContinue: DO dispatch message again, DON'T complete message
+ // EReqActionBusy DO dispatch message again, DON'T complete message,
+ TInt completeErr;
+
+ for (completeErr = EReqActionComplete; CurrentOperationPtr() != NULL && completeErr == EReqActionComplete; )
+ {
+ // Get the completion routine from the current TMsgOperation and then pop it
+ TFsRequestFunc doComplete = CurrentOperation().iComplete;
+ PopOperation();
+
+ // Check that a completion routine is supplied if this isn't the last TMsgOperation
+ __ASSERT_ALWAYS(iCurrentOperation == NULL || doComplete != NULL, Fault(EBadOperationIndex));
+
+ // Call the completion routine
+ if (doComplete)
+ completeErr = doComplete(this);
+
+ // Check return code is valid
+ __ASSERT_DEBUG(completeErr == EReqActionContinue || completeErr == EReqActionBusy || completeErr == EReqActionComplete || completeErr == EReqActionOwnedByPlugin, Fault(EBadOperationCompletionCode));
+ }
+
+ // a set of flags to determine what actions to take for each return code
+ enum
+ {
+ EDispatch = 0x01, // dispatch request
+ EComplete = 0x02, // complete request
+ EFree =0x04, // free request
+ EResetPostInitialised = 0x08, // call iPostInitialise again
+ EDispatchToFront = 0x10 // dispatch to back of drive thread queue
+ };
+ const TUint actions[8] =
+ {
+ // 0 - EReqActionContinue
+ EDispatch,
+ // 1 - unused
+ 0,
+ // 2 - unused
+ 0,
+ // 3 - unused
+ 0,
+ // 4 - EReqActionCompleteAndDispatch
+ EDispatch | EComplete | EResetPostInitialised | EDispatchToFront,
+ // 5 - EReqActionOwnedByPlugin
+ 0,
+ // 6 - EReqActionBusy
+ EDispatch | EResetPostInitialised,
+ // 7 - EReqActionComplete
+ EComplete | EFree,
+ };
+
+ TUint actionFlags = actions[((TUint32) completeErr) & 0x00000007];
+
+ // To dispatch to drive thread and intercept before DoRequestL()
+ // we must re-call iPostInitialise(), so reset iPostInitialised flag
+ if (actionFlags & EResetPostInitialised)
+ {
+ // can only postpone the request if there's a PostInitialise() function
+ __ASSERT_DEBUG(iOperation->iPostInitialise , Fault(EBadOperationCompletionCode));
+ SetState(EReqStatePostInitialise);
+ }
+
+
+
+ TInt dispatchError = KErrNone;
+ TBool completeMessage = (iLastError != KErrNone) || (iIsCompleted && (actionFlags & EComplete));
+
+ // Need to lock drive to prevent both file server and drive thread from completing the same message (!)
+ // or the dispatched thread from freeing the message before the first thread has completed it
+ TDrive* drive = iDrive;
+ if (drive)
+ drive->Lock();
+
+ // don't go back up plugin chain once message has been completed
+ if (completeMessage)
+ EnablePostIntercept(EFalse);
+
+ if (actionFlags & EDispatch)
+ {
+ __ASSERT_DEBUG(((actionFlags & EFree) == 0), Fault(EInvalidCompletionFlags));
+ __ASSERT_DEBUG (iCurrentPlugin == NULL, Fault(EInvalidMsgState));
+ dispatchError = DispatchToDrive(EFalse, actionFlags & EDispatchToFront);
+ }
+
+
+ if ((actionFlags & EComplete) && IsExpectedResult(iLastError) && !IsPluginSpecific() && !IsNotifierSpecific())
+ DoNotify(KErrNone);
+
+
+ if (completeMessage)
+ {
+ iIsCompleted = EFalse;
+ TInt msgHandle = Message().Handle();
+ if ((msgHandle != KLocalMessageHandle) && (msgHandle != 0))
+ Message().Complete(iLastError);
+ if (IsPluginRequest())
+ CFsPlugin::Complete(this, iLastError);
+ }
+
+ if(iOperation->Function() == EFsFileSubClose)
+ {
+ HBufC* pFileName = (HBufC*) I64HIGH(ScratchValue64());
+ if(pFileName)
+ {
+ delete pFileName;
+ SetScratchValue(NULL);
+ }
+ }
+
+ if (drive)
+ drive->UnLock();
+
+ if (actionFlags & EFree)
+ Free();
+
+ // if the dispatch failed, then continue with popping MessageOps from the stack.
+ if (dispatchError != KErrNone)
+ Complete(dispatchError);
+ }
+
+void CFsMessageRequest::DoNotify(TInt aError)
+//
+//
+//
+ {
+ __PRINT1(_L("----- CFsMessageRequest::DoNotify() with %d"),aError);
+
+ TInt driveNumber = DriveNumber();
+
+ if(aError==KErrNone)
+ {
+ if(!(FsNotify::IsChangeQueEmpty(driveNumber)))
+ FsNotify::HandleChange(this,driveNumber);
+ if ((driveNumber != KDriveInvalid) && !(FsNotify::IsDiskSpaceQueEmpty(driveNumber)))
+ FsNotify::HandleDiskSpace(this, DriveNumber());
+
+#ifdef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
+ if (iOperation->iFunction == EFsFileWrite)
+ {
+ CFileShare* share = (CFileShare*) this->ScratchValue();
+ CFileCB* file = &share->File();
+ CFileCache* fileCache = file->FileCache();
+
+ // Manage notifications for write with no cache or a write-through
+ if (!fileCache || !fileCache->IsDirty())
+ {
+ FsNotificationManager::HandleChange((CFsClientMessageRequest&)*this);
+ }
+ }
+ else if((iOperation->iFunction == EFsFileWriteDirty) && FsNotificationManager::IsInitialised())
+ {
+ CFileShare* share;
+ CFileCB* file;
+ GetFileFromScratch(this, share, file);
+
+ TFileName path;
+ path.Append(file->DriveNumber() + 'A');
+ path.Append(':');
+ path.Append(file->FileName().Des());
+
+ // Manage notifications for write with caching enabled
+ FsNotificationManager::HandleChange((CFsClientMessageRequest*)this, path, TFsNotification::EFileChange);
+ }
+ else if(IsNotifierSupported())
+ {
+ FsNotificationManager::HandleChange((CFsClientMessageRequest&)*this);
+ }
+#endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
+ }
+ }
+
+
+void CFsMessageRequest::Free()
+//
+//
+//
+ {
+ __THRD_PRINT1(_L("CFsMessageRequest::Free() isAllocated=%d"), IsAllocated());
+
+ SetScratchValue(0); // this should close the CFsObject
+
+ if(!IsAllocated())
+ delete(this);
+ else iOperation = NULL;
+
+ }
+
+TInt CFsMessageRequest::DoInitialise()
+//
+// returns KErrNone if Initialise succeeded normally
+// or EReqActionComplete if request completed already
+// or EReqActionBusy if request needs dispatching & initialising again
+//
+ {
+ TInt r = KErrNone;
+
+ SetState(iOperation->iPostInitialise ? EReqStatePostInitialise : EReqStateDoRequest);
+ r=Initialise();
+ if(r==KErrBadHandle)
+ {
+ // bad subsession handle so panic client
+ _LIT(KPanic,"Panic");
+ Panic(KPanic,r);
+ if(iOperation->IsOpenSubSess()) //this should be close subsession
+ RequestAllocator::OpenSubFailed(Session()); //need a close subsession fail
+ Free();
+ r = EReqActionComplete;
+ }
+ else if (r == EReqActionComplete) // completed synchronously in Initialise() function ?
+ {
+ Complete(KErrNone);
+ }
+ else if (r == EReqActionBusy || r == EReqActionPending) // request postponed or owned by file share ?
+ {
+ }
+ else if (r != KErrNone) // error
+ {
+ Complete(r);
+ r = EReqActionComplete;
+ }
+
+ return r;
+ }
+
+TInt CFsMessageRequest::PostInitialise()
+//
+// returns KErrNone if PostInitialise() succeeded normally
+// or EReqActionComplete if request completed already
+// or EReqActionBusy if request needs dispatching & initialising again
+//
+ {
+ TInt r = KErrNone;
+
+ SetState(EReqStateDoRequest);
+ if (iOperation->iPostInitialise)
+ r = iOperation->iPostInitialise(this);
+ if (r == EReqActionComplete) // completed early ?
+ {
+
+ // Start issuing the post-operation requests starting from the bottom of the chain
+ iCurrentPlugin = NULL;
+ if (PostInterceptEnabled())
+ {
+ FsPluginManager::PrevPlugin(iCurrentPlugin, this,(TBool)ETrue);
+ if(iCurrentPlugin && !iCurrentPlugin->IsPluginThread(*this))
+ {
+ SetPostOperation(ETrue);
+ Dispatch();
+ return r; // EReqActionComplete
+ }
+ }
+
+ Complete(KErrNone);
+ }
+ else if (r == EReqActionBusy) // request postponed ?
+ {
+ }
+ else if (r != KErrNone) // error
+ {
+ Complete(r);
+ r = EReqActionComplete;
+ }
+
+ return r;
+ }
+
+
+// CFsMessageRequest::Dispatch()
+//
+// If aInitialise is EFalse, just disptach request to appropriate thread -
+// don't call DoInitialise() or PostInitialise()
+//
+void CFsMessageRequest::Dispatch(TBool aInitialise, TBool aLowPriority, TBool aDispatchToFront)
+ {
+ __THRD_PRINT1(_L("CFsMessageRequest::Dispatch() req %08x"), this);
+
+ TInt r = KErrNone;
+
+ if (iReqState == EReqStateInitialise && aInitialise)
+ {
+ r = DoInitialise();
+ if (r == EReqActionComplete)
+ {
+ return;
+ }
+ else if (r == EReqActionBusy) // request postponed ?
+ {
+ SetState(EReqStateInitialise); // reinitialize when request is next processed
+ }
+ else if (r == EReqActionPending) // owned by file share ?
+ {
+ SetState(EReqStateInitialise); // reinitialize when request is next processed
+ return;
+ }
+ if(!IsPluginSpecific() && (iOwnerPlugin == NULL))
+ {
+ iCurrentPlugin = NULL;
+ iClientThreadId = 0;
+ FsPluginManager::NextPlugin(iCurrentPlugin, this, (TBool)ETrue);
+
+ // find out whether there is a plugin registered to post intercept this message
+ CFsPlugin* postInterceptPlugin = NULL;
+ if (iCurrentPlugin == NULL)
+ FsPluginManager::PrevPlugin(postInterceptPlugin, this, (TBool)ETrue);
+
+ // Save the client's thread Id for subsequent testing by CFsPlugin::IsPluginThread() - doing so on the fly
+ // is risky because some messages are completed early in which case Message().Client() will result in a panic
+ if ((iCurrentPlugin || postInterceptPlugin) && Message().Handle() != NULL && Message().Handle() != KLocalMessageHandle)
+ {
+ RThread thread;
+ Message().Client(thread, EOwnerThread);
+ iClientThreadId = thread.Id();
+ thread.Close();
+ }
+ }
+ } // initialise
+
+
+ // dispatch to plugin thread if initialised (otherwise dispatch to drive thread)
+ if (iReqState > EReqStateInitialise && DispatchToPlugin())
+ {
+ __PLUGIN_PRINT1(_L("PLUGIN: CFsMessageRequest %x dispatched to plugin (async)"), this);
+ // The request has been delivered to the plugin thread
+ // - leave the main thread now and await asynchronous completion
+ return;
+ }
+
+
+ // Is there a PostInitialise function ?
+ if (iReqState == EReqStatePostInitialise && aInitialise && r == KErrNone)
+ {
+ TInt r = PostInitialise();
+ if (r == EReqActionComplete)
+ return;
+ else if (r == EReqActionBusy) // request postponed ?
+ SetState(EReqStatePostInitialise); // reinitialize when request is next processed
+ }
+
+
+ if(!IsSeparateThread() || FsThreadManager::IsDriveSync(DriveNumber(),EFalse))
+ {
+ __PLUGIN_PRINT1(_L("PLUGIN: CFsMessageRequest %x dispatched to plugin (sync)"), this);
+ FsPluginManager::DispatchSync(this);
+ return;
+ }
+
+ r = DispatchToDrive(aLowPriority, aDispatchToFront);
+ if (r != KErrNone)
+ Complete(r);
+ }
+
+inline TInt CFsMessageRequest::DispatchToDrive(TBool aLowPriority, TBool aDispatchToFront)
+ {
+ TInt drivenumber = DriveNumber();
+
+ if (drivenumber < EDriveA || drivenumber > EDriveZ)
+ return KErrNotSupported;
+
+ FsThreadManager::LockDrive(drivenumber);
+
+ CDriveThread* dT=NULL;
+ TInt r = FsThreadManager::GetDriveThread(drivenumber,&dT);
+
+ if(r == KErrNone)
+ {
+ CRequestThread* pT = (CRequestThread*)dT;
+
+ if (FsThreadManager::IsDriveHung(drivenumber))
+ r = KErrNotReady;
+ else if (aDispatchToFront)
+ pT->DeliverFront(this);
+ else
+ pT->DeliverBack(this, aLowPriority);
+ }
+ else if (r == KErrAccessDenied)
+ {
+ Process();
+ }
+
+ FsThreadManager::UnlockDrive(drivenumber);
+
+ return r;
+ }
+
+void CFsMessageRequest::Dispatch()
+ {
+ Dispatch(ETrue);
+ }
+
+TBool CFsMessageRequest::DispatchToPlugin()
+//
+//
+//
+ {
+ TInt drivenumber = DriveNumber();
+ if(iCurrentPlugin)
+ {
+ FOREVER
+ {
+ // if we've reached a plugin which is waiting for Complete(), stop going up the plugin chain
+ if(drivenumber >= 0 && IsPostOperation() && CurrentPluginWaiting())
+ {
+ // No more plug-ins need to process this request
+ iCurrentPlugin = NULL;
+ }
+
+ while(iCurrentPlugin && iCurrentPlugin->IsPluginThread(*this))
+ {
+ // Skip the current plugin if the request originated from the plugin
+ if(IsPostOperation())
+ {
+ FsPluginManager::PrevPlugin(iCurrentPlugin, this,(TBool)ETrue);
+ }
+ else
+ {
+ FsPluginManager::NextPlugin(iCurrentPlugin, this,(TBool)ETrue);
+ }
+ }
+
+ if(iCurrentPlugin)
+ {
+ TFsPluginRequest request(this);
+ __THRD_PRINT1(_L("CFsMessageRequest::DispatchToPlugin() req %08x"), this);
+
+ TInt err = iCurrentPlugin->Deliver(request);
+ if(err == KErrNone)
+ {
+
+ // The request has been delivered to the plugin thread
+ // - leave the main thread now
+ return(ETrue);
+ }
+ else if(err < KErrNone)
+ {
+ // An error has occurred
+ // - complete the message
+ Complete(err);
+ return(ETrue);
+ }
+ else if(err == KPluginMessageForward)
+ {
+ // The plugin has processed synchronously (case 1)
+ // - Pass the message on to the next plugin
+ FsPluginManager::NextPlugin(iCurrentPlugin, this,(TBool)ETrue);
+ continue;
+ }
+ else if(err == KPluginMessageComplete)
+ {
+ // The plugin has processed synchronously (case 2)
+ // - Pass the message back up the stack
+ SetPostOperation(ETrue);
+ FsPluginManager::PrevPlugin(iCurrentPlugin, this,(TBool)ETrue);
+ continue;
+ }
+ _LIT(KPanic,"Panic: F32-BAD-PLUGIN-ERROR");
+ Panic(KPanic, err);
+ }
+ else if (IsPostOperation())
+ {
+ // No more plugins are interested in this request
+ // - If in post operation, complete the request
+ Complete(GetError());
+ return(ETrue);
+ }
+ else
+ {
+ // No plugin is registered for pre-operation interception this message
+ // - pass the request onto the drive thread.
+ return EFalse;
+ }
+ }
+ }
+
+ if(iOperation->Function() == EFsDismountPlugin)
+ {
+ // Don't pass plugin dismounts to the drive thread
+ Process();
+ return(ETrue);
+ }
+
+ return EFalse;
+ }
+
+TDrive* CFsMessageRequest::Drive()
+//
+//
+//
+ {
+ return(iDrive);
+ }
+
+TDrive* CFsMessageRequest::SubstedDrive()
+//
+//
+//
+ {
+ return(iSubstedDrive);
+ }
+
+void CFsMessageRequest::SetDrive(TDrive* aDrive)
+//
+//
+//
+ {
+ iDrive=aDrive;
+ if(aDrive)
+ {
+ iDriveNumber=aDrive->DriveNumber();
+ }
+ }
+
+void CFsMessageRequest::SetSubstedDrive(TDrive* aDrive)
+//
+//
+//
+ {
+ iSubstedDrive=aDrive;
+ }
+
+const RMessage2& CFsMessageRequest::Message()
+//
+//
+//
+ {
+ return(iMessage);
+ }
+
+
+
+void CFsMessageRequest::ReStart()
+ {
+ __ASSERT_ALWAYS(CurrentOperationPtr() != NULL, Fault(EBadOperationIndex));
+
+ // restore original settings :
+ TMsgOperation& currentOperation = CurrentOperation();
+ TInt offset = currentOperation.iReadWriteArgs.iOffset;
+ currentOperation.iReadWriteArgs.iPos-= offset;
+ currentOperation.iReadWriteArgs.iTotalLength+= offset;
+ currentOperation.iReadWriteArgs.iLength = currentOperation.iReadWriteArgs.iTotalLength;
+ currentOperation.iReadWriteArgs.iOffset = 0;
+ currentOperation.iState = 0;
+ TInt function = iOperation->Function();
+ __ASSERT_ALWAYS(function == EFsFileRead || function == EFsFileWrite, Fault(EMsgRestartBadFunction));
+ }
+
+
+void CFsMessageRequest::SetOperationFunc(TInt aFunction)
+ {
+ const TOperation& oP = OperationArray[aFunction];
+ Set(oP);
+ // modified because some requests were set to PostInitialise. They are set to DoRequest in Dispatch anyway, so this is possibly ok?
+ //__ASSERT_ALWAYS(iReqState == EReqStateDoRequest, Fault(EInvalidMsgState));
+ }
+
+TInt CFsMessageRequest::PushOperation(TFsRequestFunc aCallback, TInt aNextState, TInt aFunction)
+ {
+ TMsgOperation* nextOperation;
+ TInt r = RequestAllocator::GetOperation(nextOperation);
+ if (r != KErrNone)
+ return r;
+
+
+ // Store the caller's state etc in the CURRENT TMsgOperation (if there is one)
+ if (iCurrentOperation != NULL)
+ {
+ __ASSERT_ALWAYS(aCallback, Fault(EPushOpNoCallback));
+ iCurrentOperation->iState = aNextState;
+ iCurrentOperation->iCurrentPlugin = iCurrentPlugin;
+ iCurrentOperation->iFunction = iOperation->Function();
+ iCurrentOperation->iNext = nextOperation;
+ nextOperation->iPrev = iCurrentOperation;
+ }
+
+ // store the call-back routine in the NEW TMsgOperation
+ nextOperation->iComplete = aCallback;
+ nextOperation->iState = 0;
+ if (aFunction != KOperationFunctionUnaltered && aFunction != iOperation->Function())
+ SetOperationFunc(aFunction);
+
+
+ iCurrentOperation = nextOperation;
+
+ // reset post operation state: as a plugin may push more than one TMsgOperation
+ SetPostOperation(EFalse);
+
+ return KErrNone;
+ }
+
+/**
+PushOperation()
+
+Pushes a new TMsgOperation onto this request's "stack". After this function completes the new
+TMsgOperation object becomes the "current" one (pointed at by CFsMessageRequest::iCurrentOperation).
+
+After the request has been dispatched to the drive thread, TOperation::DoRequestL() will be called.
+When this has completed, CFsMessage::Complete() is called which then pops the new TMsgOperation
+off the stack; and calls the callback routine (aCallback).
+
+@param aPos The position to read / write. Stored in the NEW TMsgOperation.
+
+@param aLength The length to read / write. Stored in the NEW TMsgOperation.
+
+@param aData A buffer to read the data from / write the data to. Stored in the NEW TMsgOperation.
+ The buffer must belong to the file server or to a plugin
+
+@param aOffset The offset onto the buffer to read from / write to. Stored in the NEW TMsgOperation.
+
+@param aCallback An optional callback routine. Stored in the OLD TMsgOperation.
+ MUST be supplied if there are one or more TMsgOperation's already on the stack
+
+@param aNextState State information private to the caller. Defaults to zero. Stored in the OLD TMsgOperation.
+
+@param aFunction An optional TFsMessage. Supplied if the caller wishes to change the TOperation
+ associated with this request. When the new TMsgOperation is popped off the stack, the
+ previous TOperation is restored. Used primarally for read-modify-write.
+
+*/
+TInt CFsMessageRequest::PushOperation(TInt64 aPos, TInt aLength, TUint8* aData, TInt aOffset, TFsRequestFunc aCallback, TInt aNextState, TInt aFunction)
+ {
+ TInt r = PushOperation(aCallback, aNextState, aFunction);
+ if (r == KErrNone)
+ CurrentOperation().Set(aPos, aLength, aData, aOffset, 0);
+ return r;
+ }
+
+
+/**
+PushOperation()
+
+Pushes a new TMsgOperation onto this request's "stack". After this function completes the new
+TMsgOperation object becomes the "current" one (pointed at by CFsMessageRequest::iCurrentOperation).
+
+After the request has been dispatched to the drive thread, TOperation::DoRequestL() will be called.
+When this has completed, CFsMessage::Complete() is called which then pops the new TMsgOperation
+off the stack; and calls the callback routine (aCallback).
+
+@param aPos The position to read / write. Stored in the NEW TMsgOperation.
+
+@param aLength The length to read / write. Stored in the NEW TMsgOperation.
+
+@param aData A buffer to read the data from / write the data to. Stored in the NEW TMsgOperation.
+ The buffer belongs to a client of the file server on the other side of an IPC boundary.
+
+@param aOffset The offset onto the buffer to read from / write to. Stored in the NEW TMsgOperation.
+
+@param aCallback An optional callback routine. Stored in the OLD TMsgOperation.
+ MUST be supplied if there are one or more TMsgOperation's already on the stack
+
+@param aNextState State information private to the caller. Defaults to zero. Stored in the OLD TMsgOperation.
+
+@param aFunction An optional TFsMessage. Supplied if the caller wishes to change the TOperation
+ associated with this request. When the new TMsgOperation is popped off the stack, the
+ previous TOperation is restored. Used primarally for read-modify-write.
+
+*/
+TInt CFsMessageRequest::PushOperation(TInt64 aPos, TInt aLength, TDesC8* aData, TInt aOffset, TFsRequestFunc aCallback, TInt aNextState, TInt aFunction)
+ {
+ TInt r = PushOperation(aCallback, aNextState, aFunction);
+ if (r == KErrNone)
+ CurrentOperation().Set(aPos, aLength, aData, aOffset, 0);
+ return r;
+ }
+
+void CFsMessageRequest::PopOperation()
+ {
+ __ASSERT_ALWAYS(iCurrentOperation != NULL, Fault(EInvalidOperationIndex));
+
+ TMsgOperation* currentOperation = iCurrentOperation;
+
+ if (iCurrentOperation->iPrev == NULL)
+ {
+ iCurrentOperation = NULL;
+ }
+ else
+ {
+ TMsgOperation* prevOperation = iCurrentOperation->iPrev;
+ prevOperation->iNext = NULL;
+ iCurrentOperation = prevOperation;
+
+ iCurrentPlugin = iCurrentOperation->iCurrentPlugin;
+
+ if (iCurrentOperation->iFunction != iOperation->Function())
+ SetOperationFunc(iCurrentOperation->iFunction);
+ }
+
+ RequestAllocator::FreeOperation(currentOperation);
+ }
+
+TMsgOperation& CFsMessageRequest::CurrentOperation()
+ {
+ __ASSERT_ALWAYS(iCurrentOperation != NULL, Fault(EInvalidOperationIndex));
+ return *iCurrentOperation;
+ }
+
+
+CFsClientMessageRequest::CFsClientMessageRequest()
+: iPoolSrc (0),
+ iPoolDest(0)
+ {
+ }
+
+// Return ETrue if there are ANY TMsgOperation's in the stack which were pushed by iCurrentPlugin
+// If there are any, then it's NOT OK to dispatch this message to the plugin thread as it will be
+// waiting on a semaphore which is only cleared by Complete()
+TBool CFsMessageRequest::CurrentPluginWaiting()
+ {
+ if (iOwnerPlugin == iCurrentPlugin)
+ return ETrue;
+
+ // find out which plugin (if any) was the last to push a TMsgOperation
+ TMsgOperation* currentOperation;
+
+ for (currentOperation = iCurrentOperation ? iCurrentOperation->iPrev : NULL;
+ currentOperation != NULL;
+ currentOperation = currentOperation->iPrev)
+ {
+ if (currentOperation->iCurrentPlugin == iCurrentPlugin)
+ return ETrue;
+ }
+
+ return EFalse;
+ }
+
+
+TBool CFsMessageRequest::IsPluginRequest()
+ {
+ if(iOwnerPlugin) // Check the previous operation had a plugin)
+ {
+ return ETrue;
+ }
+ return EFalse;
+ }
+
+
+void CFsClientMessageRequest::Free()
+//
+//
+//
+ {
+ __THRD_PRINT(_L("CFsClientMessageRequest::Free()"));
+ __ASSERT_ALWAYS(CurrentOperationPtr() == NULL, Fault(EFreeingMsgWithMsgOp));
+ if (iPoolSrc)
+ {
+ TParsePool::Release(iPoolSrc);
+ iPoolSrc = 0;
+ }
+
+ if (iPoolDest)
+ {
+ TParsePool::Release(iPoolDest);
+ iPoolDest = 0;
+ }
+
+ SetScratchValue(0); // this should close the CFsObject
+ iOperation = NULL;
+ RequestAllocator::FreeRequest(this);
+ }
+
+
+TInt CFsClientMessageRequest::AllocParseObjects(const TOperation& aOperation)
+ {
+ __ASSERT_ALWAYS(iPoolSrc == NULL && iPoolDest == NULL, Fault(ETParsePoolGet));
+
+ if (aOperation.iFlags & EParseSrc)
+ {
+ iPoolSrc = TParsePool::Get();
+ if (iPoolSrc == NULL)
+ return KErrNoMemory;
+ }
+ if (aOperation.iFlags & EParseDst)
+ {
+ iPoolDest = TParsePool::Get();
+ if (iPoolDest == NULL)
+ return KErrNoMemory;
+ }
+ return KErrNone;
+ }
+
+TParse& CFsClientMessageRequest::Src()
+//
+//
+ {
+ __ASSERT_ALWAYS(iPoolSrc, Fault(ETParsePoolGet));
+ return (iPoolSrc->GetObject());
+ }
+
+TParse& CFsClientMessageRequest::Dest()
+//
+//
+//
+ {
+ __ASSERT_ALWAYS(iPoolDest, Fault(ETParsePoolGet));
+ return (iPoolDest->GetObject());
+ }
+
+
+
+TParsePool* TParsePool::iFreeHead = 0;
+TParsePool* TParsePool::iClosedHead = 0;
+TInt TParsePool::iCountFree = 0;
+RFastLock TParsePool::iLock;
+
+
+TParsePool::TParsePool()
+: iNext (iFreeHead),
+ iPrev (0),
+ iFree (ETrue)
+ {
+ }
+
+TInt TParsePool::Init()
+ {
+ return iLock.CreateLocal();
+ }
+
+TParsePool* TParsePool::Get()
+// Gets a TParsePool object from the free list. If the free list does
+// not contain any TParsePool objects, additional objects are manufactured.
+// Returns NULL if unable to allocate a new object
+ {
+ iLock.Wait();
+
+ TParsePool* pObject = 0;
+
+ // If we don't have anything in the free list, allocate some more...
+ if (iCountFree < 1)
+ {
+ __ASSERT_DEBUG(iFreeHead == NULL, Fault(ETParsePoolGet));
+ for (TInt i = 0; i < KEBlockSize; i++)
+ {
+ // if allocation fails break out of the loop.
+ pObject = new TParsePool;
+ if (pObject == NULL)
+ break;
+
+ iCountFree++;
+
+ if (iFreeHead)
+ iFreeHead->iPrev = pObject;
+
+ iFreeHead = pObject;
+ }
+ }
+
+ // if we failed to allocate even a single object, return NULL
+ if (iCountFree < 1)
+ {
+ iLock.Signal();
+ return NULL;
+ }
+
+
+ __ASSERT_ALWAYS(iFreeHead != NULL, Fault(ETParsePoolGet));
+
+ pObject = iFreeHead;
+ pObject->iFree = EFalse;
+
+
+ // Remove the head of the free list...
+ iFreeHead = pObject->iNext;
+ if (iFreeHead)
+ iFreeHead->iPrev = 0;
+ iCountFree--;
+
+ // ... and add it to the closed list
+ pObject->iNext = iClosedHead;
+ pObject->iPrev = 0;
+ if (iClosedHead)
+ iClosedHead->iPrev = pObject;
+ iClosedHead = pObject;
+
+ iLock.Signal();
+
+ return pObject;
+ }
+
+
+void TParsePool::Release(TParsePool* aObject)
+//
+// Release a sub-sequence of TParsePool objects back to the free list.
+//
+ {
+ __ASSERT_ALWAYS(aObject != NULL && !aObject->iFree, Fault(ETParsePoolGet));
+
+ iLock.Wait();
+
+ aObject->iFree = ETrue;
+
+ // Get the objects either side of the one we're interested in
+ TParsePool* pPrevious = aObject->iPrev;
+ TParsePool* pNext = aObject->iNext;
+
+ // Remove it from the closed list
+ if (pPrevious)
+ pPrevious->iNext = pNext;
+ else
+ iClosedHead = pNext;
+
+ if (pNext)
+ pNext->iPrev = pPrevious;
+
+
+ // Now add it to the free list
+ aObject->iNext = iFreeHead;
+ aObject->iPrev = 0;
+ if (iFreeHead)
+ iFreeHead->iPrev = aObject;
+
+ iFreeHead = aObject;
+ iCountFree++;
+
+ iLock.Signal();
+ }
+
+
+CFsInternalRequest::CFsInternalRequest()
+//
+//
+//
+ {
+ // iStatus=NULL;
+ // iIsAllocated=EFalse;
+ }
+
+void CFsInternalRequest::Set(const TOperation& aOperation,CSessionFs* aSession)
+//
+//
+//
+ {
+ CFsRequest::Set(aOperation,aSession);
+ }
+
+void CFsInternalRequest::Process()
+//
+//
+//
+ {
+ __THRD_PRINT(_L("CFsInternalRequest::Process()"));
+ TInt r=KErrNone;
+ TRAPD(leaveValue,r=iOperation->DoRequestL(this));
+ // internal requests should never fail
+ __ASSERT_ALWAYS(leaveValue==KErrNone && (r==KErrNone||r==EReqActionBusy),Fault(EInternalRequestProcess));
+
+ // request postponed ? (e.g. if a page used by file cache is busy).
+ if (r == EReqActionBusy)
+ {
+ Dispatch();
+ return;
+ }
+
+ Complete(r);
+ }
+
+
+void CFsInternalRequest::Complete(TInt aError)
+//
+//
+//
+ {
+ __PRINT1(_L("CFsInternalRequest::Complete() with %d"),aError);
+ TInt func = Operation()->Function();
+ if(func==KCancelSession || func==KCancelPlugin || func==KFlushDirtyData)
+ {
+ __ASSERT_DEBUG(ThreadHandle()!=0 && !FsThreadManager::IsDisconnectThread(),Fault(EInternalRequestComplete1));
+ RThread t;
+ t.SetHandle(ThreadHandle());
+ TRequestStatus* s=&Status();
+ t.RequestComplete(s,aError);
+ Free();
+ }
+ else if(func == KDispatchObjectClose)
+ {
+ TFsCloseObject::Complete(this);
+ Free();
+ }
+ else if(func==KFileShareClose)
+ {
+ if (aError == EReqActionBusy)
+ {
+ Dispatch();
+ }
+ else
+ {
+ TFsCloseFileShare::Complete(this);
+ Free();
+ }
+ }
+ else
+ Fault(EInternalRequestComplete3);
+ }
+
+void CFsInternalRequest::Dispatch()
+//
+//
+//
+ {
+ __THRD_PRINT(_L("CFsInternalRequest::Dispatch()"));
+ __ASSERT_ALWAYS(Initialise()==KErrNone,Fault(EInternalRequestDispatch1));
+
+ if(iCurrentPlugin && Operation()->Function() == KCancelPlugin)
+ {
+ TFsPluginRequest request(this);
+ TInt r = iCurrentPlugin->Deliver(request);
+ __ASSERT_ALWAYS(r == KErrNone, Fault(EInternalRequestDispatchCancelPlugin));
+ }
+ else
+ {
+ TInt drivenumber = DriveNumber();
+ FsThreadManager::LockDrive(drivenumber);
+ // shouldn't dispath if no drive available
+ __ASSERT_ALWAYS(FsThreadManager::IsDriveAvailable(drivenumber,EFalse) && !FsThreadManager::IsDriveSync(drivenumber,EFalse),Fault(EInternalRequestDispatch2));
+ CDriveThread* dT=NULL;
+ TInt r=FsThreadManager::GetDriveThread(drivenumber,&dT);
+ __THRD_PRINT2(_L("deliver to thread 0x%x, drive number %d"),dT,drivenumber);
+ __ASSERT_ALWAYS(r==KErrNone && dT,Fault(EInternalRequestDispatch3));
+ CRequestThread* pT = (CRequestThread*)dT;
+ TInt func = Operation()->Function();
+ if(func == KDispatchObjectClose || func == KFileShareClose || func == KFlushDirtyData)
+ pT->DeliverBack(this);
+ else
+ pT->DeliverFront(this);
+ FsThreadManager::UnlockDrive(drivenumber);
+ }
+ }
+
+void CFsInternalRequest::Free()
+//
+//
+//
+ {
+ __THRD_PRINT1(_L("CFsInternalRequest::Free() isAllocated=%d"),IsAllocated());
+
+ SetScratchValue(0); // this should close the CFsObject
+
+ if(!IsAllocated())
+ delete(this);
+ }
+
+void CFsDisconnectRequest::Dispatch()
+//
+//
+//
+ {
+ __THRD_PRINT(_L("CFsDisconnectRequest::Dispatch()"));
+ // no need to lock
+ TInt r=Initialise();
+ __ASSERT_ALWAYS(r==KErrNone,Fault(EDisconnectRequestDispatch1));
+ CRequestThread* pT=FsThreadManager::GetDisconnectThread();
+ __ASSERT_ALWAYS(pT,Fault(EDisconnectRequestDispatch2));
+ pT->DeliverBack(this);
+ }
+
+void CFsDisconnectRequest::Process()
+//
+//
+//
+ {
+ __THRD_PRINT(_L("CFsDisconnectRequest::Process()"));
+ TInt r=KErrNone;
+ TRAPD(leaveValue,r=iOperation->DoRequestL(this));
+ leaveValue=leaveValue; // just to make compiler happy
+ __ASSERT_DEBUG(leaveValue==KErrNone && r==KErrNone,Fault(EDisonncectRequestProcess));
+ Complete(r);
+ }
+
+void CFsDisconnectRequest::Complete(TInt aError)
+//
+//
+//
+ {
+ __PRINT1(_L("CFsDisconnectRequest::Complete() with %d"),aError);
+ __ASSERT_ALWAYS(aError==KErrNone,Fault(EDisconnectRequestComplete));
+ // set session disconnect reqeust to NULL
+ // will be freed in CFsMessageRequest::Free()
+ Session()->iDisconnectRequest=NULL;
+ // now delete session
+ TheFileServer->SessionQueueLockWait();
+ delete(Session());
+ TheFileServer->SessionQueueLockSignal();
+ // NB Must complete the message AFTER the session has been deleted...
+ Message().Complete(aError);
+ delete(this);
+ }
+
+
+/**
+Create a new synchronous message scheduler
+*/
+CFsSyncMessageScheduler* CFsSyncMessageScheduler::NewL()
+ {
+ __PRINT(_L("CFsSyncMessageScheduler::NewL()"));
+
+ CFsSyncMessageScheduler* pSelf = new(ELeave)CFsSyncMessageScheduler();
+
+ CleanupStack::PushL(pSelf);
+ pSelf->ConstructL();
+ CleanupStack::Pop();
+
+ return(pSelf);
+ }
+
+
+/**
+Construct a synchronous message scheduler
+*/
+CFsSyncMessageScheduler::CFsSyncMessageScheduler()
+ : CActive(EPriorityHigh),
+ iList(_FOFF(CFsRequest,iLink))
+ {
+ __PRINT(_L("CFsSyncMessageScheduler::CFsSyncMessageScheduler()"));
+ }
+
+
+/**
+Second-phase constructor
+*/
+
+void CFsSyncMessageScheduler::ConstructL()
+ {
+ __PRINT(_L("CFsSyncMessageScheduler::ConstructL()"));
+
+ User::LeaveIfError(iLock.CreateLocal());
+ User::LeaveIfError(iThread.Open(RThread().Id()));
+
+ CActiveScheduler::Add(this);
+ }
+
+
+/**
+Synchronous message scheduler
+ - dispatch any synchronous requests that were queued via ::Dispatch
+*/
+void CFsSyncMessageScheduler::RunL()
+ {
+ __PRINT(_L(">> CFsSyncMessageScheduler::RunL()"));
+
+ FOREVER
+ {
+ iLock.Wait();
+ if(iList.IsEmpty())
+ {
+ break;
+ }
+ else
+ {
+ CFsRequest* request = iList.First();
+ request->iLink.Deque();
+ iLock.Signal();
+ __PRINT1(_L(" CFsSyncMessageScheduler - Dispatching message %08x"), request);
+ request->Process();
+ }
+ }
+
+ iSignalled = EFalse;
+ iStatus = KRequestPending;
+ SetActive();
+ iLock.Signal();
+
+ __PRINT(_L("<< CFsSyncMessageScheduler::RunL()"));
+ }
+
+
+/**
+DoCancel - Not Implemented
+*/
+void CFsSyncMessageScheduler::DoCancel()
+ {
+ __PRINT(_L("CFsSyncMessageScheduler::DoCancel"));
+ }
+
+
+/**
+Queue synchronous requests to be processed in main thread context
+ - called when synchronous messages are passed from plugin threads
+*/
+void CFsSyncMessageScheduler::Dispatch(CFsRequest* aRequest)
+ {
+ __PRINT1(_L("CFsSyncMessageScheduler::Dispatch(%08x)"), aRequest);
+
+ // Accquire lock and add request to queue.
+ iLock.Wait();
+ iList.AddFirst(*aRequest);
+
+ if(!iSignalled)
+ {
+ // set iSignalled in case another thread (plug-in) is calling dispatch, then release lock.
+ iSignalled = ETrue;
+ iLock.Signal();
+
+ // signal main thread.
+ TRequestStatus* s = &iStatus;
+ iThread.RequestComplete(s, KErrNone);
+ }
+ else
+ {
+ // main thread already signalled, just release lock.
+ iLock.Signal();
+ }
+ }
+
+
+/**
+Complete outstanding requests for the specified session
+*/
+void CFsSyncMessageScheduler::CompleteSessionRequests(CSessionFs* aSession, TInt aValue)
+ {
+ __PRINT2(_L("FsPluginManager::CompleteSessionRequests(%08x, %d)"), aSession, aValue);
+
+ iLock.Wait();
+ TDblQueIter<CFsRequest> q(iList);
+ CFsRequest* pR;
+ while((pR=q++)!=NULL)
+ {
+ if(pR->Session()==aSession)
+ {
+ pR->iLink.Deque();
+ pR->Complete(aValue);
+ }
+ }
+ iLock.Signal();
+ }
+