Update contrib.
1 // Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // f32\sfile\sf_request.cpp
19 #include "sf_file_cache.h"
20 #ifdef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
21 #include "sf_notifier.h"
22 #endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
28 CFsClientMessageRequest* RequestAllocator::iFreeHead;
29 CFsClientMessageRequest* RequestAllocator::iCloseHead;
30 TInt RequestAllocator::iAllocNum;
31 TInt RequestAllocator::iAllocNumOperation;
32 TMsgOperation* RequestAllocator::iFreeHeadSupOp;
34 #if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
35 TInt RequestAllocator::iAllocated;
37 RFastLock RequestAllocator::iCacheLock;
39 void RequestAllocator::Initialise()
44 #if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
51 TInt RequestAllocator::AllocRequest(TInt aNum)
53 // Allocates a group of request objects
57 if(iAllocNum < KMaxRequestAllocated)
59 __CACHE_PRINT(_L("RequestAllocator::AllocRequest() Not reached the limit"));
60 CFsClientMessageRequest* list;
61 CFsClientMessageRequest* start;
62 list = new CFsClientMessageRequest[KAllocReqBlock];
67 // Make sure the constructors are called for every element in the array
68 // - some compilers don't do this
69 for(TInt j=0; j<KAllocReqBlock; j++)
71 CFsClientMessageRequest* request = &list[j];
72 new(request) CFsClientMessageRequest();
75 iAllocNum += KAllocReqBlock;
76 CFsClientMessageRequest* last;
77 for(i=1;i<KAllocReqBlock;i++)
83 list->iNext = iFreeHead;
89 __CACHE_PRINT1(_L("RequestAllocator::AllocRequest() Limit exceeded Count = %d"),aNum);
90 CFsClientMessageRequest* request;
93 request=new CFsClientMessageRequest;
96 #if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
99 request->SetAllocated();
100 request->iNext=iFreeHead;
107 void RequestAllocator::FreeRequest(CFsClientMessageRequest* aRequest)
112 __CACHE_PRINT1(_L("PLUGIN: RequestAllocator::FreeRequest for %x"), aRequest);
113 if(aRequest->IsAllocated())
115 __CACHE_PRINT(_L("RequestAllocator::FreeRequest() Allocated request"));
117 #if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
123 __CACHE_PRINT(_L("RequestAllocator::FreeRequest() returning to free list"));
125 aRequest->iNext = iFreeHead;
127 aRequest->SetSubstedDrive(NULL);
131 void RequestAllocator::OpenSubFailed(CSessionFs* aSession)
133 // Move requst from closed list to free list
136 __ASSERT_DEBUG(iCloseHead!=NULL,Fault(ERequestAllocatorOpenSubFailed)); // On arriving here Close Queue is supposed to be empty
137 __ASSERT_ALWAYS(aSession!=NULL,Fault(ERequestAllocatorOpenSubFailed));
138 if (iCloseHead==NULL)
143 CFsClientMessageRequest* rp = iCloseHead;
144 iCloseHead = rp->iNext;
146 // dec the number of closed requests owned by this session
147 aSession->CloseRequestCountDec();
150 if(rp->IsAllocated())
152 __CACHE_PRINT(_L("RequestAllocator::OpenSubFailed() Allocated request"));
154 #if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
160 __CACHE_PRINT(_L("RequestAllocator::OpenSubFailed()"));
163 rp->iNext = iFreeHead;
175 TInt RequestAllocator::GetMessageRequest(const TOperation& aOperation,const RMessage2& aMessage,CFsClientMessageRequest* &aRequest)
177 // tries to get a pre allocated message from the cache. Failing that allocates one indivisualy
180 if(aOperation.IsOpenSubSess())
182 __CACHE_PRINT(_L("++RequestAllocator::GetMessageRequest() Open sub-sess"));
184 if(iFreeHead == NULL || iFreeHead->iNext == NULL)
186 if(AllocRequest(2)!= KErrNone)
192 aRequest= iFreeHead; //get our request from free head
193 iFreeHead = iFreeHead->iNext->iNext; //set next but one as new free head read for next
195 aRequest->iNext->iNext = NULL; //seperate our request and close from free list
196 CFsClientMessageRequest* CRp = aRequest->iNext;
197 aRequest->iNext = NULL;
200 CRp->iNext = iCloseHead; //set second one as a reserved (tail) close request
206 ((CSessionFs*) aMessage.Session())->CloseRequestCountInc();
208 else if(aOperation.IsCloseSubSess())
210 __CACHE_PRINT(_L("++RequestAllocator::GetMessageRequest() Close sub-sess"));
212 CFsObject* pO = SessionObjectFromHandle(aMessage.Int3(),0,reinterpret_cast<CSessionFs*>(aMessage.Session()));
214 return KErrBadHandle;
216 CObjPromotion* pm = (CObjPromotion*)pO;
217 TInt function = aMessage.Function();
218 switch(function & KIpcFunctionMask)
220 case EFsFormatSubClose:
222 if(pm->UniqueID() != Formats->UniqueID())
224 return KErrBadHandle;
230 if(pm->UniqueID() != Dirs->UniqueID())
232 return KErrBadHandle;
236 case EFsFileSubClose:
238 if(pm->UniqueID() != FileShares->UniqueID())
240 return KErrBadHandle;
246 if(pm->UniqueID() != RawDisks->UniqueID())
248 return KErrBadHandle;
252 case EFsPluginSubClose:
254 if(pm->UniqueID() != FsPluginManager::iPluginConns->UniqueID())
256 return KErrBadHandle;
260 #ifdef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
261 case EFsNotificationSubClose:
263 if(pm->UniqueID() != FsNotificationManager::iNotifyRequests->UniqueID())
265 return KErrBadHandle;
269 #endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
271 Fault(ECloseSubBadMessage);
275 aRequest = iCloseHead;
276 iCloseHead = aRequest->iNext;
277 ((CSessionFs*) aMessage.Session())->CloseRequestCountDec();
278 aRequest->iNext = NULL;
280 if((function & KIpcFunctionMask)!= EFsPluginSubClose &&
281 (function & KIpcFunctionMask)!= EFsNotificationSubClose)
283 aRequest->SetDrive(&TheDrives[((CFsDispatchObject*)pO)->DriveNumber()]);
286 aRequest->SetScratchValue((TUint)pO);
290 __CACHE_PRINT(_L("++RequestAllocator::GetMessageRequest() "));
294 if(AllocRequest(1) != KErrNone)
300 aRequest = iFreeHead;
301 iFreeHead = aRequest->iNext;
302 aRequest->iNext= NULL;
309 // pre-allocate any TParse objects needed by this request
310 if (aRequest->AllocParseObjects(aOperation) != KErrNone)
316 __CACHE_PRINT1(_L("--RequestAllocator::GetMessageRequest() allocated %08x"), aRequest);
322 #if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
323 TInt RequestAllocator::CloseCount()
325 CFsClientMessageRequest* list=iCloseHead;
333 TInt RequestAllocator::FreeCount()
336 CFsClientMessageRequest* list=iFreeHead;
345 TInt RequestAllocator::AllocOperation()
347 // Allocates a group of TMsgOperation objects
349 // Must be called with iCacheLock held
352 if(iAllocNumOperation < KMaxOperationAllocated)
354 __CACHE_PRINT(_L("RequestAllocator::AllocOperation() Not reached the limit"));
356 TMsgOperation* start;
357 list = new TMsgOperation[KAllocReqBlock];
362 for(TInt j=0; j<KAllocReqBlock; j++)
364 TMsgOperation* request = &list[j];
365 request->iIsAllocated = EFalse;
368 iAllocNumOperation += KAllocReqBlock;
370 for(i=1;i<KAllocReqBlock;i++)
376 list->iNext = iFreeHeadSupOp;
377 iFreeHeadSupOp = start;
382 __CACHE_PRINT(_L("RequestAllocator::AllocOperation() Limit exceeded"));
383 TMsgOperation* request;
385 request=new TMsgOperation;
388 #if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
391 request->iIsAllocated = ETrue;
392 request->iNext=iFreeHeadSupOp;
393 iFreeHeadSupOp=request;
398 TInt RequestAllocator::GetOperation(TMsgOperation* &aOperation)
400 // tries to get a pre allocated subop from the cache. Failing that allocates one individualy
404 __CACHE_PRINT(_L("RequestAllocator::GetOperation() "));
408 if(AllocOperation() != KErrNone)
414 aOperation = iFreeHeadSupOp;
415 iFreeHeadSupOp = aOperation->iNext;
416 aOperation->iNext = aOperation->iPrev = NULL;
422 void RequestAllocator::FreeOperation(TMsgOperation* aOperation)
427 if(aOperation->iIsAllocated)
429 __CACHE_PRINT(_L("RequestAllocator::FreeOperation() Allocated subop"));
431 #if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
437 __CACHE_PRINT(_L("RequestAllocator::FreeOperation() returning to free list"));
439 aOperation->iNext = iFreeHeadSupOp; // NB backward link only used when request in in use
440 iFreeHeadSupOp = aOperation;
446 CFsRequest::CFsRequest()
450 : iOperation(NULL),iDriveNumber(KDriveInvalid)
453 CFsRequest::~CFsRequest()
459 void CFsRequest::Set(const TOperation& aOperation,CSessionFs* aSession)
465 SetState(EReqStateInitialise);
467 iOperation = const_cast<TOperation*>(&aOperation);
469 iIsCompleted = aOperation.IsCompleted();
471 iDriveNumber = KDriveInvalid;
472 iCurrentPlugin = NULL;
474 iDirectToDrive = EFalse;
476 iFlags &= ~(EFreeChanged | EPostInterceptEnabled | EPostOperation | EFsObjectOpen);
480 void CFsRequest::Set(CSessionFs* aSession)
485 __ASSERT_DEBUG(iOperation,Fault(EBaseRequestSet1));
487 SetState(EReqStateInitialise);
490 iIsCompleted = iOperation->IsCompleted();
492 iDriveNumber = KDriveInvalid;
493 iCurrentPlugin = NULL;
495 iDirectToDrive = EFalse;
497 iFlags &= ~(EFreeChanged | EPostInterceptEnabled | EPostOperation | EFsObjectOpen);
502 TParse& CFsRequest::Src()
507 Fault(EBaseRequestSrc);
511 TParse& CFsRequest::Dest()
516 Fault(EBaseRequestDest);
520 TDrive* CFsRequest::Drive()
525 Fault(EBaseRequestDrive);
529 TDrive* CFsRequest::SubstedDrive()
534 Fault(EBaseRequestSubstedDrive);
538 void CFsRequest::SetDrive(TDrive* /*aDrive*/)
543 Fault(EBaseRequestSetDrive);
546 void CFsRequest::SetSubstedDrive(TDrive* /*aDrive*/)
551 Fault(EBaseRequestSetSubstedDrive);
554 TInt CFsRequest::GetSlot(TFsPluginRequest::TF32ArgType aType)
556 if(iOperation->Arg(0) == aType) return 0;
557 if(iOperation->Arg(1) == aType) return 1;
558 if(iOperation->Arg(2) == aType) return 2;
559 if(iOperation->Arg(3) == aType) return 3;
565 TBool CFsMessageRequest::IsNotifierSpecific() const
567 #ifndef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
570 TInt function = iOperation->iFunction;
571 return( function == EFsNotificationAdd ||
572 function == EFsNotificationBuffer ||
573 function == EFsNotificationCancel ||
574 function == EFsNotificationOpen ||
575 function == EFsNotificationRemove ||
576 function == EFsNotificationRequest ||
577 function == EFsNotificationSubClose);
578 #endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
582 TBool CFsMessageRequest::IsNotifierSupported() const
584 #ifndef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
587 TInt function = iOperation->iFunction;
588 return( function == EFsDelete ||
589 function == EFsRmDir ||
590 function == EFsMkDir ||
591 function == EFsFormatNext ||
592 function == EFsFileCreate ||
593 function == EFsFileReplace ||
594 function == EFsFileRename ||
595 function == EFsRename ||
596 function == EFsReplace ||
597 function == EFsSetDriveName ||
598 function == EFsSetVolume ||
599 function == EFsSetEntry ||
600 function == EFsFileSetAtt ||
601 function == EFsFileSet ||
602 function == EFsMountFileSystem ||
603 function == EFsDismountFileSystem ||
604 function == EFsFileSetSize ||
605 function == EFsFileWrite ||
606 function == EFsFileWriteDirty ||
607 function == EFsRawDiskWrite ||
608 function == EFsMountFileSystemScan);
609 #endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
613 TInt CFsRequest::Read(TFsPluginRequest::TF32ArgType aType, TInt& aVal)
615 if(iOperation->Arg(0) == aType) { aVal = Message().Int0(); return KErrNone; }
616 if(iOperation->Arg(1) == aType) { aVal = Message().Int1(); return KErrNone; }
617 if(iOperation->Arg(2) == aType) { aVal = Message().Int2(); return KErrNone; }
618 if(iOperation->Arg(3) == aType) { aVal = Message().Int3(); return KErrNone; }
620 return KErrNotSupported;
624 TInt CFsRequest::Read(TFsPluginRequest::TF32ArgType aType, TUint& aVal)
626 if(iOperation->Arg(0) == aType) { aVal = (TUint)Message().Int0(); return KErrNone; }
627 if(iOperation->Arg(1) == aType) { aVal = (TUint)Message().Int1(); return KErrNone; }
628 if(iOperation->Arg(2) == aType) { aVal = (TUint)Message().Int2(); return KErrNone; }
629 if(iOperation->Arg(3) == aType) { aVal = (TUint)Message().Int3(); return KErrNone; }
631 return KErrNotSupported;
634 TInt CFsRequest::Read(TFsPluginRequest::TF32ArgType aType, TInt64& aVal)
636 TPckg<TInt64> pkVal(aVal);
637 // EFsFileLock, EFsFileUnLock, EFsFileSeek and EFsFileSetSize need special treatment
638 if(iOperation->Arg(0) == aType)
640 if((iOperation->Function()==EFsFileLock) ||
641 (iOperation->Function()==EFsFileUnLock) )
643 if(IsDescData(KMsgPtr0))
644 Read(KMsgPtr0,pkVal);
646 aVal = MAKE_TINT64(0, Message().Int0()); // Position is unsigned value
650 if((iOperation->Function()==EFsFileSeek) || // Seek offset (input paramater)
651 (iOperation->Function()==EFsFileSize) || // Size (output paramater)
652 (iOperation->Function()==EFsFileSetSize) ) // Size to be set (input paramater)
654 if(IsDescData(KMsgPtr0))
655 Read(KMsgPtr0,pkVal);
657 aVal = Message().Int0(); // Seek offset / Size is signed value
661 aVal = Message().Int0();
665 // EFsFileLock and EFsFileUnLock need special treatment
666 if(iOperation->Arg(1) == aType)
668 if((iOperation->Function()==EFsFileLock) ||
669 (iOperation->Function()==EFsFileUnLock) )
671 if(IsDescData(KMsgPtr1))
672 Read(KMsgPtr1,pkVal);
674 aVal = MAKE_TINT64(0, Message().Int1()); // Length is unsigned value
678 aVal = Message().Int1();
682 // EFsFileRead, EFsFileWrite, EFsFileSeek and EFsReadFileSection need special treatment
683 if(iOperation->Arg(2) == aType)
685 if((iOperation->Function()==EFsFileRead) ||
686 (iOperation->Function()==EFsFileWrite) )
688 if(IsDescData(KMsgPtr2))
689 Read(KMsgPtr2,pkVal);
692 if(Message().Int2() == (TInt)I64LOW(KCurrentPosition64))
693 aVal = KCurrentPosition64; // Position is KCurrentPosition64 (-1)
695 aVal = MAKE_TINT64(0,Message().Int2()); // Position is unsigned value
700 if(iOperation->Function()==EFsFileSeek)
702 if(IsDescData(KMsgPtr2))
703 Read(KMsgPtr2,pkVal);
705 aVal = Message().Int2(); // New position is signed value
709 if(iOperation->Function()==EFsReadFileSection)
711 if(IsDescData(KMsgPtr2))
712 Read(KMsgPtr2,pkVal);
714 aVal = MAKE_TINT64(0,Message().Int2()); // Position is unsigned value
718 aVal = Message().Int2();
722 if(iOperation->Arg(3) == aType)
724 aVal = Message().Int3();
728 return KErrNotSupported;
731 void CFsRequest::SetAndOpenScratchValue(const TInt64& aValue)
733 if (IsFsObjectOpen())
735 ((CFsDispatchObject*) I64LOW(iScratchValue))->Close();
736 SetFsObjectOpen(EFalse);
738 if (I64LOW(aValue) && iOperation && (iOperation->iFlags & EFileShare))
740 ((CFsDispatchObject*) I64LOW(aValue))->Open();
741 SetFsObjectOpen(ETrue);
743 iScratchValue = aValue;
747 TInt CFsRequest::Read(TFsPluginRequest::TF32ArgType aType, TDes8& aDes, TInt aOffset)
749 TInt slot = GetSlot(aType);
751 return Read(slot, aDes, aOffset);
752 return KErrNotSupported;
756 TInt CFsRequest::Read(TFsPluginRequest::TF32ArgType aType, TDes16& aDes, TInt aOffset)
758 TInt slot = GetSlot(aType);
760 return Read(slot, aDes, aOffset);
761 return KErrNotSupported;
765 TInt CFsRequest::Write(TFsPluginRequest::TF32ArgType aType, const TDesC8& aDes, TInt aOffset)
767 TInt slot = GetSlot(aType);
769 return Write(slot, aDes, aOffset);
770 return KErrNotSupported;
774 TInt CFsRequest::Write(TFsPluginRequest::TF32ArgType aType, const TDesC16& aDes, TInt aOffset)
776 TInt slot = GetSlot(aType);
778 return Write(slot, aDes, aOffset);
779 return KErrNotSupported;
783 TInt CFsRequest::Read(const TInt aMsgPtr,TDes8 &aDes)
785 if (Message().Handle() == KLocalMessageHandle)
787 TDesC8* pDes = (TDesC8*) ((const RLocalMessage*) &Message())->Arg(aMsgPtr);
788 if (aDes.MaxLength() < pDes->Length())
794 return Message().Read(aMsgPtr,aDes,0);
798 TInt CFsRequest::Read(const TInt aMsgPtr,TDes8 &aDes,TInt anOffset)
800 if (Message().Handle() == KLocalMessageHandle)
802 TDesC8* pDes = (TDesC8*) ((const RLocalMessage*) &Message())->Arg(aMsgPtr);
803 if (aDes.MaxLength() < pDes->Length() + anOffset)
805 aDes.SetLength(pDes->Length() + anOffset);
806 aDes.MidTPtr(anOffset).Copy(*pDes);
810 return Message().Read(aMsgPtr,aDes,anOffset);
814 TInt CFsRequest::Read(const TInt aMsgPtr,TDes16 &aDes)
816 if (Message().Handle() == KLocalMessageHandle)
818 TDesC16* pDes = (TDesC16*) ((const RLocalMessage*) &Message())->Arg(aMsgPtr);
819 if (aDes.MaxLength() < pDes->Length())
825 return Message().Read(aMsgPtr,aDes,0);
829 TInt CFsRequest::Read(const TInt aMsgPtr,TDes16 &aDes,TInt anOffset)
831 if (Message().Handle() == KLocalMessageHandle)
833 TDesC16* pDes = (TDesC16*) ((const RLocalMessage*) &Message())->Arg(aMsgPtr);
834 if (aDes.MaxLength() < pDes->Length() + anOffset)
836 aDes.SetLength(pDes->Length() + anOffset);
837 aDes.MidTPtr(anOffset).Copy(*pDes);
841 return Message().Read(aMsgPtr,aDes,anOffset);
845 TInt CFsRequest::Write(const TInt aMsgNum,const TDesC8 &aDes)
847 if (Message().Handle() == KLocalMessageHandle)
849 TDes8* pDes = (TDes8*) ((const RLocalMessage*) &Message())->Arg(aMsgNum);
850 if (pDes->MaxLength() < aDes.Length())
856 return Message().Write(aMsgNum,aDes,0);
860 TInt CFsRequest::Write(const TInt aMsgNum,const TDesC8 &aDes,TInt anOffset)
862 if (Message().Handle() == KLocalMessageHandle)
864 TDes8* pDes = (TDes8*) ((const RLocalMessage*) &Message())->Arg(aMsgNum);
865 if (pDes->MaxLength() < aDes.Length() + anOffset)
867 pDes->SetLength(aDes.Length() + anOffset);
868 pDes->MidTPtr(anOffset).Copy(aDes);
872 return Message().Write(aMsgNum,aDes,anOffset);
876 TInt CFsRequest::Write(const TInt aMsgNum,const TDesC16 &aDes)
878 if (Message().Handle() == KLocalMessageHandle)
880 TDes16* pDes = (TDes16*) ((const RLocalMessage*) &Message())->Arg(aMsgNum);
881 if (pDes->MaxLength() < aDes.Length())
887 return Message().Write(aMsgNum,aDes,0);
891 TInt CFsRequest::Write(const TInt aMsgNum,const TDesC16 &aDes,TInt anOffset)
893 if (Message().Handle() == KLocalMessageHandle)
895 TDes16* pDes = (TDes16*) ((const RLocalMessage*) &Message())->Arg(aMsgNum);
896 if (pDes->MaxLength() < aDes.Length() + anOffset)
898 pDes->SetLength(aDes.Length() + anOffset);
899 pDes->MidTPtr(anOffset).Copy(aDes);
903 return Message().Write(aMsgNum,aDes,anOffset);
907 void CFsRequest::ReadL(const TInt aMsgPtr,TDes8 &aDes)
908 { User::LeaveIfError(Read(aMsgPtr,aDes)); }
910 void CFsRequest::ReadL(const TInt aMsgPtr,TDes8 &aDes,TInt anOffset)
911 { User::LeaveIfError(Read(aMsgPtr,aDes,anOffset)); }
913 void CFsRequest::ReadL(const TInt aMsgPtr,TDes16 &aDes)
914 { User::LeaveIfError(Read(aMsgPtr,aDes)); }
916 void CFsRequest::ReadL(const TInt aMsgPtr,TDes16 &aDes,TInt anOffset)
917 { User::LeaveIfError(Read(aMsgPtr,aDes,anOffset)); }
919 void CFsRequest::WriteL(const TInt aMsgNum,const TDesC8 &aDes)
920 { User::LeaveIfError(Write(aMsgNum,aDes)); }
922 void CFsRequest::WriteL(const TInt aMsgNum,const TDesC8 &aDes,TInt anOffset)
923 { User::LeaveIfError(Write(aMsgNum,aDes,anOffset)); }
925 void CFsRequest::WriteL(const TInt aMsgNum,const TDesC16 &aDes)
926 { User::LeaveIfError(Write(aMsgNum,aDes)); }
928 void CFsRequest::WriteL(const TInt aMsgNum,const TDesC16 &aDes,TInt anOffset)
929 { User::LeaveIfError(Write(aMsgNum,aDes,anOffset)); }
933 @param aMsgNum message argument index
934 @return client side descriptor length
936 TInt CFsRequest::GetDesLength(const TInt aMsgNum)
938 if (Message().Handle() == KLocalMessageHandle)
940 TDes8* pDes = (TDes8*) ((const RLocalMessage*) &Message())->Arg(aMsgNum);
941 return pDes->Length();
945 return Message().GetDesLength(aMsgNum);
949 const RMessage2& CFsRequest::Message()
954 Fault(EBaseRequestMessage);
960 void CFsMessageRequest::Set(const RMessage2& aMessage,CSessionFs* aSession)
962 // For reuseable request
968 CFsRequest::Set(aSession);
969 SetFreeChanged(EFalse);
970 EnablePostIntercept(ETrue);
974 void CFsMessageRequest::Set(const RMessage2& aMessage,const TOperation& aOperation,CSessionFs* aSession)
983 CFsRequest::Set(aOperation,aSession);
984 SetFreeChanged(EFalse);
985 EnablePostIntercept(ETrue);
988 void CFsMessageRequest::Set(const TOperation& aOperation)
990 iOperation=const_cast<TOperation*>(&aOperation);
993 void CFsMessageRequest::Process()
995 // Process the request - (passing to a plugin or a drive thread)
998 __THRD_PRINT3(_L("CFsMessageRequest::Process() req %08x state %d plugin 0x%x"), this, iReqState, iCurrentPlugin);
1000 // initialise request - if not initialised already
1001 if (iReqState == EReqStateInitialise)
1003 TInt r = DoInitialise();
1004 if (r == EReqActionComplete)
1008 else if (r == EReqActionBusy) // request postponed ?
1010 SetState(EReqStateInitialise);
1014 else if (r == KErrNone && iCurrentPlugin) // dispatch to plugin thread ?
1023 if (IsPostOperation())
1025 ProcessPostOperation();
1029 if(!IsPluginSpecific())
1031 ProcessPreOperation();
1037 // Is there a PostInitialise function ?
1038 if (iReqState == EReqStatePostInitialise)
1040 TInt r = PostInitialise();
1041 if (r == EReqActionComplete)
1045 else if (r == EReqActionBusy) // request postponed ?
1047 SetState(EReqStatePostInitialise);
1053 ProcessDriveOperation();
1056 void CFsMessageRequest::ProcessPostOperation()
1058 // Process the message in post operation mode (handled by the current plugin)
1061 TInt err = KErrNone;
1062 if(!iCurrentPlugin->IsPluginThread(*this))
1064 // The request hasn't come from this plugin so it's safe to dispatch
1065 TFsPluginRequest request(this);
1066 TRAPD(leaveValue, err = iCurrentPlugin->DoRequestL(request));
1067 if(leaveValue != KErrNone)
1069 Panic(KFsClient,leaveValue);
1070 if(iOperation->IsOpenSubSess())
1071 RequestAllocator::OpenSubFailed(Session());
1076 if(!IsExpectedResult(err))
1083 // Find the previous plugin in the chain and dispatch
1084 // - If no more plugins are interested in this message, then complete
1085 FsPluginManager::PrevPlugin(iCurrentPlugin, this, ETrue);
1086 if(iCurrentPlugin == NULL)
1088 Complete(GetError());
1097 void CFsMessageRequest::ProcessPreOperation()
1099 // Process the message in pre operation mode (handled by the current plugin)
1102 TInt err = KErrNone;
1103 if(!iCurrentPlugin->IsPluginThread(*this))
1105 // The request hasn't come from this plugin so it's safe to dispatch
1106 TFsPluginRequest request(this);
1107 TRAPD(leaveValue, err = iCurrentPlugin->DoRequestL(request));
1108 __PLUGIN_PRINT1(_L("PLUGIN: CFsMessageRequest:: %x processed by plugin"), this);
1110 if((iOperation->Function() == EFsDismountPlugin) && (err != KErrPermissionDenied))
1112 TRAP(leaveValue, err = iOperation->DoRequestL(this));
1115 if(leaveValue != KErrNone)
1117 Panic(KFsClient,leaveValue);
1118 if(iOperation->IsOpenSubSess()) //this should be close subsession
1119 RequestAllocator::OpenSubFailed(Session()); //need a close subsession fail
1127 // Find the next plugin in the chain and dispatch
1128 // - If no more plugins are interested in this message,
1129 // then Dispatch() will process the request in drive/main thread context.
1130 FsPluginManager::NextPlugin(iCurrentPlugin, this,(TBool)ETrue);
1131 if(iCurrentPlugin && IsPostOperation())
1132 SetPostOperation(EFalse);
1136 // KErrCompletion may be returned by the plugin to
1137 // indicate that it has process the message itself (do post-intercept)
1138 else if (err == KErrCompletion)
1140 // Find the previous plugin in the chain and dispatch
1141 // - If no more plugins are interested in this message, then complete
1142 FsPluginManager::PrevPlugin(iCurrentPlugin, this,(TBool)ETrue);
1143 if(iCurrentPlugin != NULL)
1145 SetPostOperation(ETrue);
1161 void CFsMessageRequest::ProcessDriveOperation()
1163 // Process the message in drive (or main thread) context
1167 // A new request is to be processed - kick off the inactivity/finalisation timer...
1168 FsThreadManager::StartFinalisationTimer(iDriveNumber);
1170 TInt err = KErrNone;
1172 TRAPD(leaveValue, err = iOperation->DoRequestL(this));
1174 // Cancel hung state if a request from the drive thread has finished
1175 FsThreadManager::SetDriveHung(DriveNumber(), EFalse);
1177 if(leaveValue != KErrNone)
1179 Panic(KFsClient,leaveValue);
1180 if(iOperation->IsOpenSubSess())
1181 RequestAllocator::OpenSubFailed(Session());
1186 // request postponed ? (e.g. if a page used by file cache is busy,
1187 // or because of fair scheduling).
1188 if (err == EReqActionBusy)
1196 if(!IsExpectedResult(err) || IsPluginSpecific())
1198 // no need to call DoNotify here since that requires err==KErrNone
1206 // Start issuing the post-operation requests starting from the bottom of the chain
1207 iCurrentPlugin = NULL;
1208 if (PostInterceptEnabled())
1210 FsPluginManager::PrevPlugin(iCurrentPlugin, this,(TBool)ETrue);
1211 if(iCurrentPlugin && !iCurrentPlugin->IsPluginThread(*this))
1213 SetPostOperation(ETrue);
1214 if (DispatchToPlugin())
1219 Complete(GetError());
1223 void CFsMessageRequest::Complete(TInt aError)
1228 __THRD_PRINT2(_L("----- CFsMessageRequest::Complete() req %08x with %d"), this, aError);
1230 if (aError==KErrNoMemory)
1232 if (iDrive) // Not all message requests are associated with a drive!
1235 iDrive->DriveInfo(di);
1236 if (di.iType == EMediaRam)
1237 aError = KErrNoMemory;
1240 if(aError!=KErrNone)
1242 if(iOperation->IsOpenSubSess())
1243 RequestAllocator::OpenSubFailed(Session());
1246 iLastError = aError;
1248 // Call the current MessageOp's completion routine - if this returns EReqActionComplete,
1249 // then pop the request and call the next MessageOps's completion routine.
1250 // Do this until there are no more MessageOp's on the stack.
1252 // Completion return codes:
1253 // EReqActionOwnedByPlugin: DON'T dispatch message again, DON'T complete message
1254 // EReqActionComplete: DON'T dispatch message again, DO complete message
1255 // EReqActionContinue: DO dispatch message again, DON'T complete message
1256 // EReqActionBusy DO dispatch message again, DON'T complete message,
1259 for (completeErr = EReqActionComplete; CurrentOperationPtr() != NULL && completeErr == EReqActionComplete; )
1261 // Get the completion routine from the current TMsgOperation and then pop it
1262 TFsRequestFunc doComplete = CurrentOperation().iComplete;
1265 // Check that a completion routine is supplied if this isn't the last TMsgOperation
1266 __ASSERT_ALWAYS(iCurrentOperation == NULL || doComplete != NULL, Fault(EBadOperationIndex));
1268 // Call the completion routine
1270 completeErr = doComplete(this);
1272 // Check return code is valid
1273 __ASSERT_DEBUG(completeErr == EReqActionContinue || completeErr == EReqActionBusy || completeErr == EReqActionComplete || completeErr == EReqActionOwnedByPlugin, Fault(EBadOperationCompletionCode));
1276 // a set of flags to determine what actions to take for each return code
1279 EDispatch = 0x01, // dispatch request
1280 EComplete = 0x02, // complete request
1281 EFree =0x04, // free request
1282 EResetPostInitialised = 0x08, // call iPostInitialise again
1283 EDispatchToFront = 0x10 // dispatch to back of drive thread queue
1285 const TUint actions[8] =
1287 // 0 - EReqActionContinue
1295 // 4 - EReqActionCompleteAndDispatch
1296 EDispatch | EComplete | EResetPostInitialised | EDispatchToFront,
1297 // 5 - EReqActionOwnedByPlugin
1299 // 6 - EReqActionBusy
1300 EDispatch | EResetPostInitialised,
1301 // 7 - EReqActionComplete
1305 TUint actionFlags = actions[((TUint32) completeErr) & 0x00000007];
1307 // To dispatch to drive thread and intercept before DoRequestL()
1308 // we must re-call iPostInitialise(), so reset iPostInitialised flag
1309 if (actionFlags & EResetPostInitialised)
1311 // can only postpone the request if there's a PostInitialise() function
1312 __ASSERT_DEBUG(iOperation->iPostInitialise , Fault(EBadOperationCompletionCode));
1313 SetState(EReqStatePostInitialise);
1318 TInt dispatchError = KErrNone;
1319 TBool completeMessage = (iLastError != KErrNone) || (iIsCompleted && (actionFlags & EComplete));
1321 // Need to lock drive to prevent both file server and drive thread from completing the same message (!)
1322 // or the dispatched thread from freeing the message before the first thread has completed it
1323 TDrive* drive = iDrive;
1327 // don't go back up plugin chain once message has been completed
1328 if (completeMessage)
1329 EnablePostIntercept(EFalse);
1331 if (actionFlags & EDispatch)
1333 __ASSERT_DEBUG(((actionFlags & EFree) == 0), Fault(EInvalidCompletionFlags));
1334 __ASSERT_DEBUG (iCurrentPlugin == NULL, Fault(EInvalidMsgState));
1335 dispatchError = DispatchToDrive(EFalse, actionFlags & EDispatchToFront);
1339 if ((actionFlags & EComplete) && IsExpectedResult(iLastError) && !IsPluginSpecific() && !IsNotifierSpecific())
1343 if (completeMessage)
1345 iIsCompleted = EFalse;
1346 TInt msgHandle = Message().Handle();
1347 if ((msgHandle != KLocalMessageHandle) && (msgHandle != 0))
1348 Message().Complete(iLastError);
1349 if (IsPluginRequest())
1350 CFsPlugin::Complete(this, iLastError);
1353 if(iOperation->Function() == EFsFileSubClose)
1355 HBufC* pFileName = (HBufC*) I64HIGH(ScratchValue64());
1359 SetScratchValue(NULL);
1366 if (actionFlags & EFree)
1369 // if the dispatch failed, then continue with popping MessageOps from the stack.
1370 if (dispatchError != KErrNone)
1371 Complete(dispatchError);
1374 void CFsMessageRequest::DoNotify(TInt aError)
1379 __PRINT1(_L("----- CFsMessageRequest::DoNotify() with %d"),aError);
1381 TInt driveNumber = DriveNumber();
1383 if(aError==KErrNone)
1385 if(!(FsNotify::IsChangeQueEmpty(driveNumber)))
1386 FsNotify::HandleChange(this,driveNumber);
1387 if ((driveNumber != KDriveInvalid) && !(FsNotify::IsDiskSpaceQueEmpty(driveNumber)))
1388 FsNotify::HandleDiskSpace(this, DriveNumber());
1390 #ifdef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
1391 if (iOperation->iFunction == EFsFileWrite)
1393 CFileShare* share = (CFileShare*) this->ScratchValue();
1394 CFileCB* file = &share->File();
1395 CFileCache* fileCache = file->FileCache();
1397 // Manage notifications for write with no cache or a write-through
1398 if (!fileCache || !fileCache->IsDirty())
1400 FsNotificationManager::HandleChange((CFsClientMessageRequest&)*this);
1403 else if((iOperation->iFunction == EFsFileWriteDirty) && FsNotificationManager::IsInitialised())
1407 GetFileFromScratch(this, share, file);
1410 path.Append(file->DriveNumber() + 'A');
1412 path.Append(file->FileName().Des());
1414 // Manage notifications for write with caching enabled
1415 FsNotificationManager::HandleChange((CFsClientMessageRequest*)this, path, TFsNotification::EFileChange);
1417 else if(IsNotifierSupported())
1419 FsNotificationManager::HandleChange((CFsClientMessageRequest&)*this);
1421 #endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
1426 void CFsMessageRequest::Free()
1431 __THRD_PRINT1(_L("CFsMessageRequest::Free() isAllocated=%d"), IsAllocated());
1433 SetScratchValue(0); // this should close the CFsObject
1437 else iOperation = NULL;
1441 TInt CFsMessageRequest::DoInitialise()
1443 // returns KErrNone if Initialise succeeded normally
1444 // or EReqActionComplete if request completed already
1445 // or EReqActionBusy if request needs dispatching & initialising again
1450 SetState(iOperation->iPostInitialise ? EReqStatePostInitialise : EReqStateDoRequest);
1452 if(r==KErrBadHandle)
1454 // bad subsession handle so panic client
1455 _LIT(KPanic,"Panic");
1457 if(iOperation->IsOpenSubSess()) //this should be close subsession
1458 RequestAllocator::OpenSubFailed(Session()); //need a close subsession fail
1460 r = EReqActionComplete;
1462 else if (r == EReqActionComplete) // completed synchronously in Initialise() function ?
1466 else if (r == EReqActionBusy || r == EReqActionPending) // request postponed or owned by file share ?
1469 else if (r != KErrNone) // error
1472 r = EReqActionComplete;
1478 TInt CFsMessageRequest::PostInitialise()
1480 // returns KErrNone if PostInitialise() succeeded normally
1481 // or EReqActionComplete if request completed already
1482 // or EReqActionBusy if request needs dispatching & initialising again
1487 SetState(EReqStateDoRequest);
1488 if (iOperation->iPostInitialise)
1489 r = iOperation->iPostInitialise(this);
1490 if (r == EReqActionComplete) // completed early ?
1493 // Start issuing the post-operation requests starting from the bottom of the chain
1494 iCurrentPlugin = NULL;
1495 if (PostInterceptEnabled())
1497 FsPluginManager::PrevPlugin(iCurrentPlugin, this,(TBool)ETrue);
1498 if(iCurrentPlugin && !iCurrentPlugin->IsPluginThread(*this))
1500 SetPostOperation(ETrue);
1502 return r; // EReqActionComplete
1508 else if (r == EReqActionBusy) // request postponed ?
1511 else if (r != KErrNone) // error
1514 r = EReqActionComplete;
1521 // CFsMessageRequest::Dispatch()
1523 // If aInitialise is EFalse, just disptach request to appropriate thread -
1524 // don't call DoInitialise() or PostInitialise()
1526 void CFsMessageRequest::Dispatch(TBool aInitialise, TBool aLowPriority, TBool aDispatchToFront)
1528 __THRD_PRINT1(_L("CFsMessageRequest::Dispatch() req %08x"), this);
1532 if (iReqState == EReqStateInitialise && aInitialise)
1535 if (r == EReqActionComplete)
1539 else if (r == EReqActionBusy) // request postponed ?
1541 SetState(EReqStateInitialise); // reinitialize when request is next processed
1543 else if (r == EReqActionPending) // owned by file share ?
1545 SetState(EReqStateInitialise); // reinitialize when request is next processed
1548 if(!IsPluginSpecific() && (iOwnerPlugin == NULL))
1550 iCurrentPlugin = NULL;
1551 iClientThreadId = 0;
1552 FsPluginManager::NextPlugin(iCurrentPlugin, this, (TBool)ETrue);
1554 // find out whether there is a plugin registered to post intercept this message
1555 CFsPlugin* postInterceptPlugin = NULL;
1556 if (iCurrentPlugin == NULL)
1557 FsPluginManager::PrevPlugin(postInterceptPlugin, this, (TBool)ETrue);
1559 // Save the client's thread Id for subsequent testing by CFsPlugin::IsPluginThread() - doing so on the fly
1560 // is risky because some messages are completed early in which case Message().Client() will result in a panic
1561 if ((iCurrentPlugin || postInterceptPlugin) && Message().Handle() != NULL && Message().Handle() != KLocalMessageHandle)
1564 Message().Client(thread, EOwnerThread);
1565 iClientThreadId = thread.Id();
1572 // dispatch to plugin thread if initialised (otherwise dispatch to drive thread)
1573 if (iReqState > EReqStateInitialise && DispatchToPlugin())
1575 __PLUGIN_PRINT1(_L("PLUGIN: CFsMessageRequest %x dispatched to plugin (async)"), this);
1576 // The request has been delivered to the plugin thread
1577 // - leave the main thread now and await asynchronous completion
1582 // Is there a PostInitialise function ?
1583 if (iReqState == EReqStatePostInitialise && aInitialise && r == KErrNone)
1585 TInt r = PostInitialise();
1586 if (r == EReqActionComplete)
1588 else if (r == EReqActionBusy) // request postponed ?
1589 SetState(EReqStatePostInitialise); // reinitialize when request is next processed
1593 if(!IsSeparateThread() || FsThreadManager::IsDriveSync(DriveNumber(),EFalse))
1595 __PLUGIN_PRINT1(_L("PLUGIN: CFsMessageRequest %x dispatched to plugin (sync)"), this);
1596 FsPluginManager::DispatchSync(this);
1600 r = DispatchToDrive(aLowPriority, aDispatchToFront);
1605 inline TInt CFsMessageRequest::DispatchToDrive(TBool aLowPriority, TBool aDispatchToFront)
1607 TInt drivenumber = DriveNumber();
1609 if (drivenumber < EDriveA || drivenumber > EDriveZ)
1610 return KErrNotSupported;
1612 FsThreadManager::LockDrive(drivenumber);
1614 CDriveThread* dT=NULL;
1615 TInt r = FsThreadManager::GetDriveThread(drivenumber,&dT);
1619 CRequestThread* pT = (CRequestThread*)dT;
1621 if (FsThreadManager::IsDriveHung(drivenumber))
1623 else if (aDispatchToFront)
1624 pT->DeliverFront(this);
1626 pT->DeliverBack(this, aLowPriority);
1628 else if (r == KErrAccessDenied)
1633 FsThreadManager::UnlockDrive(drivenumber);
1638 void CFsMessageRequest::Dispatch()
1643 TBool CFsMessageRequest::DispatchToPlugin()
1645 // Common route: Receive -> Process -> Dispatch -> DispatchToPlugin
1648 TInt drivenumber = DriveNumber();
1653 // if we've reached a plugin which is waiting for Complete(), stop going up the plugin chain
1654 if(drivenumber >= 0 && IsPostOperation() && CurrentPluginWaiting())
1656 // No more plug-ins need to process this request
1657 iCurrentPlugin = NULL;
1660 while(iCurrentPlugin && iCurrentPlugin->IsPluginThread(*this))
1662 // Skip the current plugin if the request originated from the plugin
1663 if(IsPostOperation())
1665 FsPluginManager::PrevPlugin(iCurrentPlugin, this,(TBool)ETrue);
1669 FsPluginManager::NextPlugin(iCurrentPlugin, this,(TBool)ETrue);
1675 TFsPluginRequest request(this);
1676 __THRD_PRINT1(_L("CFsMessageRequest::DispatchToPlugin() req %08x"), this);
1678 TInt err = iCurrentPlugin->Deliver(request);
1682 // The request has been delivered to the plugin thread
1683 // - leave the main thread now
1686 else if(err < KErrNone)
1688 // An error has occurred
1689 // - complete the message
1693 else if(err == KPluginMessageForward)
1695 // The plugin has processed synchronously (case 1)
1696 // - Pass the message on to the next plugin
1697 if(FsFunction() != EFsPluginOpen)
1699 FsPluginManager::NextPlugin(iCurrentPlugin, this,(TBool)ETrue);
1702 else // FsFunction == EFsPluginOpen
1705 * PluginOpen requests should not be passed down the plugin stack.
1709 iCurrentPlugin = NULL;
1713 else if(err == KPluginMessageComplete)
1715 // The plugin has processed synchronously (case 2)
1716 // - Pass the message back up the stack
1717 SetPostOperation(ETrue);
1718 FsPluginManager::PrevPlugin(iCurrentPlugin, this,(TBool)ETrue);
1721 _LIT(KPanic,"Panic: F32-BAD-PLUGIN-ERROR");
1724 else if (IsPostOperation())
1726 // No more plugins are interested in this request
1727 // - If in post operation, complete the request
1728 Complete(GetError());
1733 // No plugin is registered for pre-operation interception this message
1734 // - pass the request onto the drive thread.
1740 if(iOperation->Function() == EFsDismountPlugin)
1742 // Don't pass plugin dismounts to the drive thread
1750 TDrive* CFsMessageRequest::Drive()
1758 TDrive* CFsMessageRequest::SubstedDrive()
1763 return(iSubstedDrive);
1766 void CFsMessageRequest::SetDrive(TDrive* aDrive)
1774 iDriveNumber=aDrive->DriveNumber();
1778 void CFsMessageRequest::SetSubstedDrive(TDrive* aDrive)
1783 iSubstedDrive=aDrive;
1786 const RMessage2& CFsMessageRequest::Message()
1796 void CFsMessageRequest::ReStart()
1798 __ASSERT_ALWAYS(CurrentOperationPtr() != NULL, Fault(EBadOperationIndex));
1800 // restore original settings :
1801 TMsgOperation& currentOperation = CurrentOperation();
1802 TInt offset = currentOperation.iReadWriteArgs.iOffset;
1803 currentOperation.iReadWriteArgs.iPos-= offset;
1804 currentOperation.iReadWriteArgs.iTotalLength+= offset;
1805 currentOperation.iReadWriteArgs.iLength = currentOperation.iReadWriteArgs.iTotalLength;
1806 currentOperation.iReadWriteArgs.iOffset = 0;
1807 currentOperation.iState = 0;
1808 TInt function = iOperation->Function();
1809 __ASSERT_ALWAYS(function == EFsFileRead || function == EFsFileWrite, Fault(EMsgRestartBadFunction));
1813 void CFsMessageRequest::SetOperationFunc(TInt aFunction)
1815 const TOperation& oP = OperationArray[aFunction];
1817 // modified because some requests were set to PostInitialise. They are set to DoRequest in Dispatch anyway, so this is possibly ok?
1818 //__ASSERT_ALWAYS(iReqState == EReqStateDoRequest, Fault(EInvalidMsgState));
1821 TInt CFsMessageRequest::PushOperation(TFsRequestFunc aCallback, TInt aNextState, TInt aFunction)
1823 TMsgOperation* nextOperation;
1824 TInt r = RequestAllocator::GetOperation(nextOperation);
1829 // Store the caller's state etc in the CURRENT TMsgOperation (if there is one)
1830 if (iCurrentOperation != NULL)
1832 __ASSERT_ALWAYS(aCallback, Fault(EPushOpNoCallback));
1833 iCurrentOperation->iState = aNextState;
1834 iCurrentOperation->iCurrentPlugin = iCurrentPlugin;
1835 iCurrentOperation->iFunction = iOperation->Function();
1836 iCurrentOperation->iNext = nextOperation;
1837 nextOperation->iPrev = iCurrentOperation;
1840 // store the call-back routine in the NEW TMsgOperation
1841 nextOperation->iComplete = aCallback;
1842 nextOperation->iState = 0;
1843 if (aFunction != KOperationFunctionUnaltered && aFunction != iOperation->Function())
1844 SetOperationFunc(aFunction);
1847 iCurrentOperation = nextOperation;
1849 // reset post operation state: as a plugin may push more than one TMsgOperation
1850 SetPostOperation(EFalse);
1858 Pushes a new TMsgOperation onto this request's "stack". After this function completes the new
1859 TMsgOperation object becomes the "current" one (pointed at by CFsMessageRequest::iCurrentOperation).
1861 After the request has been dispatched to the drive thread, TOperation::DoRequestL() will be called.
1862 When this has completed, CFsMessage::Complete() is called which then pops the new TMsgOperation
1863 off the stack; and calls the callback routine (aCallback).
1865 @param aPos The position to read / write. Stored in the NEW TMsgOperation.
1867 @param aLength The length to read / write. Stored in the NEW TMsgOperation.
1869 @param aData A buffer to read the data from / write the data to. Stored in the NEW TMsgOperation.
1870 The buffer must belong to the file server or to a plugin
1872 @param aOffset The offset onto the buffer to read from / write to. Stored in the NEW TMsgOperation.
1874 @param aCallback An optional callback routine. Stored in the OLD TMsgOperation.
1875 MUST be supplied if there are one or more TMsgOperation's already on the stack
1877 @param aNextState State information private to the caller. Defaults to zero. Stored in the OLD TMsgOperation.
1879 @param aFunction An optional TFsMessage. Supplied if the caller wishes to change the TOperation
1880 associated with this request. When the new TMsgOperation is popped off the stack, the
1881 previous TOperation is restored. Used primarally for read-modify-write.
1884 TInt CFsMessageRequest::PushOperation(TInt64 aPos, TInt aLength, TUint8* aData, TInt aOffset, TFsRequestFunc aCallback, TInt aNextState, TInt aFunction)
1886 TInt r = PushOperation(aCallback, aNextState, aFunction);
1888 CurrentOperation().Set(aPos, aLength, aData, aOffset, 0);
1896 Pushes a new TMsgOperation onto this request's "stack". After this function completes the new
1897 TMsgOperation object becomes the "current" one (pointed at by CFsMessageRequest::iCurrentOperation).
1899 After the request has been dispatched to the drive thread, TOperation::DoRequestL() will be called.
1900 When this has completed, CFsMessage::Complete() is called which then pops the new TMsgOperation
1901 off the stack; and calls the callback routine (aCallback).
1903 @param aPos The position to read / write. Stored in the NEW TMsgOperation.
1905 @param aLength The length to read / write. Stored in the NEW TMsgOperation.
1907 @param aData A buffer to read the data from / write the data to. Stored in the NEW TMsgOperation.
1908 The buffer belongs to a client of the file server on the other side of an IPC boundary.
1910 @param aOffset The offset onto the buffer to read from / write to. Stored in the NEW TMsgOperation.
1912 @param aCallback An optional callback routine. Stored in the OLD TMsgOperation.
1913 MUST be supplied if there are one or more TMsgOperation's already on the stack
1915 @param aNextState State information private to the caller. Defaults to zero. Stored in the OLD TMsgOperation.
1917 @param aFunction An optional TFsMessage. Supplied if the caller wishes to change the TOperation
1918 associated with this request. When the new TMsgOperation is popped off the stack, the
1919 previous TOperation is restored. Used primarally for read-modify-write.
1922 TInt CFsMessageRequest::PushOperation(TInt64 aPos, TInt aLength, TDesC8* aData, TInt aOffset, TFsRequestFunc aCallback, TInt aNextState, TInt aFunction)
1924 TInt r = PushOperation(aCallback, aNextState, aFunction);
1926 CurrentOperation().Set(aPos, aLength, aData, aOffset, 0);
1930 void CFsMessageRequest::PopOperation()
1932 __ASSERT_ALWAYS(iCurrentOperation != NULL, Fault(EInvalidOperationIndex));
1934 TMsgOperation* currentOperation = iCurrentOperation;
1936 if (iCurrentOperation->iPrev == NULL)
1938 iCurrentOperation = NULL;
1942 TMsgOperation* prevOperation = iCurrentOperation->iPrev;
1943 prevOperation->iNext = NULL;
1944 iCurrentOperation = prevOperation;
1946 iCurrentPlugin = iCurrentOperation->iCurrentPlugin;
1948 if (iCurrentOperation->iFunction != iOperation->Function())
1949 SetOperationFunc(iCurrentOperation->iFunction);
1952 RequestAllocator::FreeOperation(currentOperation);
1955 TMsgOperation& CFsMessageRequest::CurrentOperation()
1957 __ASSERT_ALWAYS(iCurrentOperation != NULL, Fault(EInvalidOperationIndex));
1958 return *iCurrentOperation;
1962 CFsClientMessageRequest::CFsClientMessageRequest()
1968 // Return ETrue if there are ANY TMsgOperation's in the stack which were pushed by iCurrentPlugin
1969 // If there are any, then it's NOT OK to dispatch this message to the plugin thread as it will be
1970 // waiting on a semaphore which is only cleared by Complete()
1971 TBool CFsMessageRequest::CurrentPluginWaiting()
1973 if (iOwnerPlugin == iCurrentPlugin)
1976 // find out which plugin (if any) was the last to push a TMsgOperation
1977 TMsgOperation* currentOperation;
1979 for (currentOperation = iCurrentOperation ? iCurrentOperation->iPrev : NULL;
1980 currentOperation != NULL;
1981 currentOperation = currentOperation->iPrev)
1983 if (currentOperation->iCurrentPlugin == iCurrentPlugin)
1991 TBool CFsMessageRequest::IsPluginRequest()
1993 if(iOwnerPlugin) // Check the previous operation had a plugin)
2001 void CFsClientMessageRequest::Free()
2006 __THRD_PRINT(_L("CFsClientMessageRequest::Free()"));
2007 __ASSERT_ALWAYS(CurrentOperationPtr() == NULL, Fault(EFreeingMsgWithMsgOp));
2010 TParsePool::Release(iPoolSrc);
2016 TParsePool::Release(iPoolDest);
2020 SetScratchValue(0); // this should close the CFsObject
2022 RequestAllocator::FreeRequest(this);
2026 TInt CFsClientMessageRequest::AllocParseObjects(const TOperation& aOperation)
2028 __ASSERT_ALWAYS(iPoolSrc == NULL && iPoolDest == NULL, Fault(ETParsePoolGet));
2030 if (aOperation.iFlags & EParseSrc)
2032 iPoolSrc = TParsePool::Get();
2033 if (iPoolSrc == NULL)
2034 return KErrNoMemory;
2036 if (aOperation.iFlags & EParseDst)
2038 iPoolDest = TParsePool::Get();
2039 if (iPoolDest == NULL)
2040 return KErrNoMemory;
2045 TParse& CFsClientMessageRequest::Src()
2049 __ASSERT_ALWAYS(iPoolSrc, Fault(ETParsePoolGet));
2050 return (iPoolSrc->GetObject());
2053 TParse& CFsClientMessageRequest::Dest()
2058 __ASSERT_ALWAYS(iPoolDest, Fault(ETParsePoolGet));
2059 return (iPoolDest->GetObject());
2064 TParsePool* TParsePool::iFreeHead = 0;
2065 TParsePool* TParsePool::iClosedHead = 0;
2066 TInt TParsePool::iCountFree = 0;
2067 RFastLock TParsePool::iLock;
2070 TParsePool::TParsePool()
2071 : iNext (iFreeHead),
2077 TInt TParsePool::Init()
2079 return iLock.CreateLocal();
2082 TParsePool* TParsePool::Get()
2083 // Gets a TParsePool object from the free list. If the free list does
2084 // not contain any TParsePool objects, additional objects are manufactured.
2085 // Returns NULL if unable to allocate a new object
2089 TParsePool* pObject = 0;
2091 // If we don't have anything in the free list, allocate some more...
2094 __ASSERT_DEBUG(iFreeHead == NULL, Fault(ETParsePoolGet));
2095 for (TInt i = 0; i < KEBlockSize; i++)
2097 // if allocation fails break out of the loop.
2098 pObject = new TParsePool;
2099 if (pObject == NULL)
2105 iFreeHead->iPrev = pObject;
2107 iFreeHead = pObject;
2111 // if we failed to allocate even a single object, return NULL
2119 __ASSERT_ALWAYS(iFreeHead != NULL, Fault(ETParsePoolGet));
2121 pObject = iFreeHead;
2122 pObject->iFree = EFalse;
2125 // Remove the head of the free list...
2126 iFreeHead = pObject->iNext;
2128 iFreeHead->iPrev = 0;
2131 // ... and add it to the closed list
2132 pObject->iNext = iClosedHead;
2135 iClosedHead->iPrev = pObject;
2136 iClosedHead = pObject;
2144 void TParsePool::Release(TParsePool* aObject)
2146 // Release a sub-sequence of TParsePool objects back to the free list.
2149 __ASSERT_ALWAYS(aObject != NULL && !aObject->iFree, Fault(ETParsePoolGet));
2153 aObject->iFree = ETrue;
2155 // Get the objects either side of the one we're interested in
2156 TParsePool* pPrevious = aObject->iPrev;
2157 TParsePool* pNext = aObject->iNext;
2159 // Remove it from the closed list
2161 pPrevious->iNext = pNext;
2163 iClosedHead = pNext;
2166 pNext->iPrev = pPrevious;
2169 // Now add it to the free list
2170 aObject->iNext = iFreeHead;
2173 iFreeHead->iPrev = aObject;
2175 iFreeHead = aObject;
2182 CFsInternalRequest::CFsInternalRequest()
2188 // iIsAllocated=EFalse;
2191 void CFsInternalRequest::Set(const TOperation& aOperation,CSessionFs* aSession)
2196 CFsRequest::Set(aOperation,aSession);
2199 void CFsInternalRequest::Process()
2204 __THRD_PRINT(_L("CFsInternalRequest::Process()"));
2206 TRAPD(leaveValue,r=iOperation->DoRequestL(this));
2207 // internal requests should never fail
2208 __ASSERT_ALWAYS(leaveValue==KErrNone && (r==KErrNone||r==EReqActionBusy),Fault(EInternalRequestProcess));
2210 // request postponed ? (e.g. if a page used by file cache is busy).
2211 if (r == EReqActionBusy)
2221 void CFsInternalRequest::Complete(TInt aError)
2226 __PRINT1(_L("CFsInternalRequest::Complete() with %d"),aError);
2227 TInt func = Operation()->Function();
2228 if(func==KCancelSession || func==KCancelPlugin || func==KFlushDirtyData)
2230 __ASSERT_DEBUG(ThreadHandle()!=0 && !FsThreadManager::IsDisconnectThread(),Fault(EInternalRequestComplete1));
2232 t.SetHandle(ThreadHandle());
2233 TRequestStatus* s=&Status();
2234 t.RequestComplete(s,aError);
2237 else if(func == KDispatchObjectClose)
2239 TFsCloseObject::Complete(this);
2242 else if(func==KFileShareClose)
2244 if (aError == EReqActionBusy)
2250 TFsCloseFileShare::Complete(this);
2255 Fault(EInternalRequestComplete3);
2258 void CFsInternalRequest::Dispatch()
2263 __THRD_PRINT(_L("CFsInternalRequest::Dispatch()"));
2264 __ASSERT_ALWAYS(Initialise()==KErrNone,Fault(EInternalRequestDispatch1));
2266 if(iCurrentPlugin && Operation()->Function() == KCancelPlugin)
2268 TFsPluginRequest request(this);
2269 TInt r = iCurrentPlugin->Deliver(request);
2270 __ASSERT_ALWAYS(r == KErrNone, Fault(EInternalRequestDispatchCancelPlugin));
2274 TInt drivenumber = DriveNumber();
2275 FsThreadManager::LockDrive(drivenumber);
2276 // shouldn't dispath if no drive available
2277 __ASSERT_ALWAYS(FsThreadManager::IsDriveAvailable(drivenumber,EFalse) && !FsThreadManager::IsDriveSync(drivenumber,EFalse),Fault(EInternalRequestDispatch2));
2278 CDriveThread* dT=NULL;
2279 TInt r=FsThreadManager::GetDriveThread(drivenumber,&dT);
2280 __THRD_PRINT2(_L("deliver to thread 0x%x, drive number %d"),dT,drivenumber);
2281 __ASSERT_ALWAYS(r==KErrNone && dT,Fault(EInternalRequestDispatch3));
2282 CRequestThread* pT = (CRequestThread*)dT;
2283 TInt func = Operation()->Function();
2284 if(func == KDispatchObjectClose || func == KFileShareClose || func == KFlushDirtyData)
2285 pT->DeliverBack(this);
2287 pT->DeliverFront(this);
2288 FsThreadManager::UnlockDrive(drivenumber);
2292 void CFsInternalRequest::Free()
2297 __THRD_PRINT1(_L("CFsInternalRequest::Free() isAllocated=%d"),IsAllocated());
2299 SetScratchValue(0); // this should close the CFsObject
2305 void CFsDisconnectRequest::Dispatch()
2310 __THRD_PRINT(_L("CFsDisconnectRequest::Dispatch()"));
2312 TInt r=Initialise();
2313 __ASSERT_ALWAYS(r==KErrNone,Fault(EDisconnectRequestDispatch1));
2314 CRequestThread* pT=FsThreadManager::GetDisconnectThread();
2315 __ASSERT_ALWAYS(pT,Fault(EDisconnectRequestDispatch2));
2316 pT->DeliverBack(this);
2319 void CFsDisconnectRequest::Process()
2324 __THRD_PRINT(_L("CFsDisconnectRequest::Process()"));
2326 TRAPD(leaveValue,r=iOperation->DoRequestL(this));
2327 leaveValue=leaveValue; // just to make compiler happy
2328 __ASSERT_DEBUG(leaveValue==KErrNone && r==KErrNone,Fault(EDisonncectRequestProcess));
2332 void CFsDisconnectRequest::Complete(TInt aError)
2337 __PRINT1(_L("CFsDisconnectRequest::Complete() with %d"),aError);
2338 __ASSERT_ALWAYS(aError==KErrNone,Fault(EDisconnectRequestComplete));
2339 // set session disconnect reqeust to NULL
2340 // will be freed in CFsMessageRequest::Free()
2341 Session()->iDisconnectRequest=NULL;
2342 // now delete session
2343 TheFileServer->SessionQueueLockWait();
2345 TheFileServer->SessionQueueLockSignal();
2346 // NB Must complete the message AFTER the session has been deleted...
2347 Message().Complete(aError);
2353 Create a new synchronous message scheduler
2355 CFsSyncMessageScheduler* CFsSyncMessageScheduler::NewL()
2357 __PRINT(_L("CFsSyncMessageScheduler::NewL()"));
2359 CFsSyncMessageScheduler* pSelf = new(ELeave)CFsSyncMessageScheduler();
2361 CleanupStack::PushL(pSelf);
2362 pSelf->ConstructL();
2363 CleanupStack::Pop();
2370 Construct a synchronous message scheduler
2372 CFsSyncMessageScheduler::CFsSyncMessageScheduler()
2373 : CActive(EPriorityHigh),
2374 iList(_FOFF(CFsRequest,iLink))
2376 __PRINT(_L("CFsSyncMessageScheduler::CFsSyncMessageScheduler()"));
2381 Second-phase constructor
2384 void CFsSyncMessageScheduler::ConstructL()
2386 __PRINT(_L("CFsSyncMessageScheduler::ConstructL()"));
2388 User::LeaveIfError(iLock.CreateLocal());
2389 User::LeaveIfError(iThread.Open(RThread().Id()));
2391 CActiveScheduler::Add(this);
2396 Synchronous message scheduler
2397 - dispatch any synchronous requests that were queued via ::Dispatch
2399 void CFsSyncMessageScheduler::RunL()
2401 __PRINT(_L(">> CFsSyncMessageScheduler::RunL()"));
2412 CFsRequest* request = iList.First();
2413 request->iLink.Deque();
2415 __PRINT1(_L(" CFsSyncMessageScheduler - Dispatching message %08x"), request);
2420 iSignalled = EFalse;
2421 iStatus = KRequestPending;
2425 __PRINT(_L("<< CFsSyncMessageScheduler::RunL()"));
2430 DoCancel - Not Implemented
2432 void CFsSyncMessageScheduler::DoCancel()
2434 __PRINT(_L("CFsSyncMessageScheduler::DoCancel"));
2439 Queue synchronous requests to be processed in main thread context
2440 - called when synchronous messages are passed from plugin threads
2442 void CFsSyncMessageScheduler::Dispatch(CFsRequest* aRequest)
2444 __PRINT1(_L("CFsSyncMessageScheduler::Dispatch(%08x)"), aRequest);
2446 // Accquire lock and add request to queue.
2448 iList.AddFirst(*aRequest);
2452 // set iSignalled in case another thread (plug-in) is calling dispatch, then release lock.
2456 // signal main thread.
2457 TRequestStatus* s = &iStatus;
2458 iThread.RequestComplete(s, KErrNone);
2462 // main thread already signalled, just release lock.
2469 Complete outstanding requests for the specified session
2471 void CFsSyncMessageScheduler::CompleteSessionRequests(CSessionFs* aSession, TInt aValue)
2473 __PRINT2(_L("FsPluginManager::CompleteSessionRequests(%08x, %d)"), aSession, aValue);
2476 TDblQueIter<CFsRequest> q(iList);
2478 while((pR=q++)!=NULL)
2480 if(pR->Session()==aSession)
2483 pR->Complete(aValue);