Update contrib.
1 // Copyright (c) 2005-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_plugin.cpp
20 #include "sf_plugin_priv.h"
22 CFsObjectCon* FsPluginManager::iPluginFactories = NULL;
23 CFsObjectCon* FsPluginManager::iPluginConns = NULL;
24 RFastLock FsPluginManager::iChainLock;
25 RPointerArray<CFsPlugin> FsPluginManager::iPluginChain;
26 CFsSyncMessageScheduler* FsPluginManager::iScheduler = NULL;
28 TBool IsPagableDrive(TInt aDrive)
30 if(LocalDrives::IsValidDriveMapping(aDrive))
32 TLocalDriveCapsBuf capsBuf;
33 if(!LocalDrives::IsProxyDrive(aDrive) && LocalDrives::GetLocalDrive(aDrive).Caps(capsBuf) && capsBuf().iDriveAtt & KDriveAttPageable)
38 return (TBool) EFalse;
42 @param aNonPagableDriveMask - a drive mask of the drives a plugin wishes to mount on
43 @return A drive mask of the drives a plugin wishes to mount on not containing any pagable drives.
45 TInt NonPagableDrivesMask(TInt aNonPagableDriveMask)
47 TInt driveMask = aNonPagableDriveMask;
48 for(TInt i = 0; i < KMaxDrives; i++)
50 //If we're interested in this drive
51 if((aNonPagableDriveMask & 1<<i) && IsPagableDrive(i))
53 driveMask ^= 1<<i; //remove this drive
59 TInt FsPluginManager::UpdateMountedDrive(CFsPlugin* aPlugin, CFsPluginFactory* aFactory,TInt aDrive)
61 if(aDrive==KPluginAutoAttach) //KPluginAutoAttach
63 if(!(aFactory->SupportedDrives()&KPluginVersionTwo))
64 { //Version 1 Plugin - Mount on all (except Z and pagble drives)
65 TInt drivesAToY = (KPluginSupportAllDrives>>1);
66 aPlugin->iMountedOn = NonPagableDrivesMask(drivesAToY);
69 { //Version 2 Plugin - Mount on what the plugin supports (except pagable drives)
70 aPlugin->iMountedOn = NonPagableDrivesMask((aFactory->SupportedDrives()&(~KPluginVersionTwo)));
73 if(!(aPlugin->iMountedOn &(~KPluginVersionTwo)))
74 { //Are we mounted on anything?
75 return KErrNotSupported;
80 // DriveZ special handling
81 if(aDrive==KPluginMountDriveZ)
84 //Mounting on a single drive
85 if(!IsPagableDrive(aDrive))
87 aPlugin->iMountedOn |= 1<<aDrive;
91 return KErrNotSupported;
95 FsPluginManager::Initialise
97 void FsPluginManager::InitialiseL()
99 iPluginFactories = TheContainer->CreateL();
100 iPluginConns = TheContainer->CreateL();
101 iPluginChain.Reset();
102 User::LeaveIfError(iChainLock.CreateLocal());
104 // Create and install the synchronous message scheduler
105 // - Messages are dispatched here from plugin threads if they are
106 // to be executed in the context of the main file server thread.
107 iScheduler = CFsSyncMessageScheduler::NewL();
112 FsPluginManager::MountPlugin
114 TInt FsPluginManager::MountPlugin(CFsPluginFactory& aPluginFactory, TInt aDrive, TInt aPos)
116 TInt uniquePosition = aPluginFactory.UniquePosition();
117 CFsPlugin* pP = NULL;
118 CFsPluginFactory* pF = &aPluginFactory;
120 //Version1 plugins could either been mounted on 1 or all drives.
121 //This isn't particularily desirable.
123 //For version2 plugins:
124 //Check whether this plugin has already been mounted
125 pP = FindByUniquePosition(uniquePosition);
126 if(pP && (aPluginFactory.iSupportedDrives&KPluginVersionTwo))
128 //if this plugin has already been mounted then
129 //Instead of trying to mount and failing with KErrInUse,
130 //lets update the iMountedOn instead.
131 return UpdateMountedDrive(pP,pF,aDrive);
135 TRAPD(err, pP = aPluginFactory.NewPluginL());
143 TFullName name = aPluginFactory.Name();
145 pP->iUniquePos=aPluginFactory.UniquePosition();
146 pP->SetDrive(aDrive);
148 //Set which drive(s?) this plugin is mounted on.
149 err = UpdateMountedDrive(pP,pF,aDrive);
157 err = InsertInPluginStack(pP,aPos);
165 err = InitPlugin(*pP);
170 aPluginFactory.IncrementMounted();
178 Must be called with the plugin chain locked.
180 void FsPluginManager::DismountPlugin(CFsPluginFactory& aPluginFactory,TInt aPos)
182 CFsPlugin* plugin=iPluginChain[aPos];
186 // Check if there is any requests for this plugin
187 // if so, deliver them to the next supporting plugin
188 TransferRequests(plugin->iThreadP);
190 plugin->iThreadP=NULL;
192 //Remove the plugin from the chain
193 iPluginChain.Remove(aPos);
194 iPluginChain.Compress();
196 //Close the plugin (destructed when CPluginThread is destructed).
202 ASSERT(0); // force panic in debug mode
205 aPluginFactory.DecrementMounted();
209 * This will iterate through a plugins request queue and
210 * search for the first occurance it finds of a CancelPluginOp
213 void FsPluginManager::GetNextCancelPluginOpRequest(CPluginThread* aPluginThread, CFsRequest*& aCancelPluginRequest)
215 __THRD_PRINT(_L("FsPluginManager::GetNextCancelPluginOpRequest"));
217 TDblQueIter<CFsRequest> iter(aPluginThread->iList);
218 CFsRequest* request = NULL;
220 while((request=iter++)!=NULL)
222 if(request->Operation()->iFunction == KCancelPlugin)
224 aCancelPluginRequest = request;
235 Transfer any outstanding requests to next/previous plugin depending on
236 if it is post filter or not
238 Must be called with the plugin chain locked.
239 Attains plugin-thread's listlock.
241 void FsPluginManager::TransferRequests(CPluginThread* aPluginThread)
243 aPluginThread->iListLock.Wait();
245 __THRD_PRINT(_L("FsPluginManager::TransferRequests - moving requests"));
248 * We are transferring requests up and down the chain
249 * because this plugin is being removed.
251 * There is a potential problem when one of the outstanding requests
252 * is CancelPluginOp which is called when the Session is being closed.
253 * The CancelPluginOp will try to cancel all of the requests on a plugin's
254 * queue which is associated with that session.
255 * DismountPlugin(and thus TransferRequests) is trying to preserve the requests
256 * by passing them along to the Next/Previous plugins.
258 * If there is a cancel in the chain we must NOT pass any requests to Previous Plugins
259 * as these have already had their chains emptied.
260 * We should also be wary of passing requests up the chain as they will simply be cancelled
261 * somewhere closer to the drive [thread].
263 * Therefore, we shall check whether there is a KCancelPlugin op in the
265 * If there is a cancelPluginOp in the chain, we will cancel of the requests
266 * that are associated with that session.
268 * After that is out of the way we preserve the remaining requests for different sessions by
271 if(!aPluginThread->iList.IsEmpty())
273 CFsRequest* cancelRequest = NULL;
274 //For every CancelPluginOp
275 while(FsPluginManager::GetNextCancelPluginOpRequest(aPluginThread, cancelRequest), cancelRequest!=NULL)
277 RDebug::Print(_L("Transferring Plugin Requests - CancelPluginOp"));
278 TDblQueIter<CFsRequest> iter(aPluginThread->iList);
279 CFsRequest* request = NULL;
281 while((request=iter++)!=NULL)
283 if(request->Session() == cancelRequest->Session() && request != cancelRequest)
285 request->iLink.Deque();
286 request->Complete(KErrCancel);
289 cancelRequest->iLink.Deque();
290 cancelRequest->Complete(KErrNone);
291 cancelRequest = NULL;
295 * Now that all requests that were to be cancelled have been cancelled,
296 * we can now go about moving the remaining ones on to , or back to,
297 * the appropriate next or previous plugins.
299 * ToDo: This next 'while' might be able to be replaced with a call to
300 * DispatchToPlugin/DispatchToDrive instead.
302 while(!aPluginThread->iList.IsEmpty())
304 CFsRequest* pR=aPluginThread->iList.First();
305 CFsMessageRequest& mR = *(CFsMessageRequest*) pR;
307 pR->iCurrentPlugin=NULL;
309 if(pR->IsPluginSpecific())
311 pR->Complete(KErrCancel);
315 if(pR->IsPostOperation())
317 //[set the plugin to] pass the request backwards in the chain
318 PrevPlugin(pR->iCurrentPlugin, &mR, EFalse);
320 else //IsPreOperations
322 //[set the plugin to] pass the request forwards in the chain
323 NextPlugin(pR->iCurrentPlugin, &mR, EFalse);
326 if(pR->iCurrentPlugin)
328 pR->iCurrentPlugin->iThreadP->DeliverBack(pR);
332 if(!pR->IsPostOperation() && (pR->DriveNumber()>=EDriveA && pR->DriveNumber()<=EDriveZ))
334 //Deliver to drive thread
335 CDriveThread* dT=NULL;
336 TInt r=FsThreadManager::GetDriveThread(pR->DriveNumber(),&dT);
337 __ASSERT_ALWAYS(r==KErrNone && dT,Fault(EFsDriveThreadError));
338 CRequestThread* pT = (CRequestThread*)dT;
343 pR->Complete(KErrCancel);
349 aPluginThread->iExit = ETrue;
350 aPluginThread->iListLock.Signal();
352 __THRD_PRINT(_L("FsPluginManager::TransferRequests - all requests moved/cancelled"));
356 Install a plugin factory
358 TInt FsPluginManager::InstallPluginFactory(CFsPluginFactory* aFactory,RLibrary aLib)
360 TInt r=aFactory->Install();
361 __PRINT1TEMP(_L("InstallPluginFactory %S"),aFactory->Name());
363 {TRAP(r,iPluginFactories->AddL(aFactory,ETrue))}
367 aFactory->SetLibrary(aLib);
374 Find a plugin factory by name
376 CFsPluginFactory* FsPluginManager::GetPluginFactory(const TDesC& aName)
380 TInt r=iPluginFactories->FindByName(h,aName);
383 return((CFsPluginFactory*)iPluginFactories->At(h));
387 Find the next plugin that supports the operation
389 @param aPlugin - On calling the function this may contain either NULL or the current plugin.
390 If it is called with NULL, then we start to look for plugins from the beginning of the chain.
391 If is is called with a plugin then we start to look after that plugin for the next one.
392 On return, aPlugin shall contain either a plugin or NULL.
394 @param aLock - If this is set to ETRUE, then the function shall lock the plugin chain.
395 If this is set to EFALSE, then the caller of the function MUST already hold the lock.
397 @param aCheckCurrentOperation - Optional, if false, will return the next plugin,
398 whether the plugin is currently registered
399 for the current function or not. (so long as mounted on the current drive)
401 TInt FsPluginManager::NextPlugin(CFsPlugin*& aPlugin, CFsMessageRequest* aMsgRequest,TBool aLock, TBool aCheckCurrentOperation)
403 if(aMsgRequest->DirectToDrive())
410 TInt function = aMsgRequest->Operation()->Function();
411 TInt drive = aMsgRequest->DriveNumber();
416 //the plugin chain lock must be held by this point.
417 TInt count = iPluginChain.Count();
422 start = iPluginChain.Find(aPlugin)+1;
424 if(start!=KErrNotFound)
426 for(TInt i=start;i<count;i++)
428 if(!aCheckCurrentOperation || iPluginChain[i]->IsRegistered(function, CFsPlugin::EPreIntercept))
430 if((function == EFsDismountPlugin) || (iPluginChain[i]->IsMounted(drive)))
433 aPlugin = iPluginChain[i];
448 Find the next plugin that supports the operation
450 @see FsPluginManager::NextPlugin
452 TInt FsPluginManager::PrevPlugin(CFsPlugin*& aPlugin, CFsMessageRequest* aMsgRequest, TBool aLock)
454 if(aMsgRequest->DirectToDrive() && (aMsgRequest->CurrentOperationPtr() != NULL))
461 TInt function = aMsgRequest->Operation()->Function();
462 TInt drive = aMsgRequest->DriveNumber();
467 //the plugin chain lock must be held by this point.
468 TInt count= iPluginChain.Count();
473 start = iPluginChain.Find(aPlugin)-1;
475 if(start!=KErrNotFound)
477 for(TInt i=start;i>=0;i--)
479 CFsPlugin* owner = aMsgRequest->iOwnerPlugin;
480 if(owner == iPluginChain[i])
483 if(iPluginChain[i]->IsRegistered(function, CFsPlugin::EPostIntercept))
485 if((function == EFsDismountPlugin) || (iPluginChain[i]->IsMounted(drive)))
488 aPlugin = iPluginChain[i];
502 Inserts the plugin in the stack (chain)
504 if aPos absolute postion, it simply inserts it
505 if aPos unique position, it walks through chain and checks the unique positions
507 TInt FsPluginManager::InsertInPluginStack(CFsPlugin*& aPlugin,TInt aPos)
510 TInt count= iPluginChain.Count();
511 if(aPos == KPluginAutoLocate)
513 TInt uPos= aPlugin->iUniquePos;
514 for(TInt i=0;i<count;i++)
516 if(uPos == iPluginChain[i]->iUniquePos)
521 if(uPos < iPluginChain[i]->iUniquePos)
523 ret=iPluginChain.Insert(aPlugin,i);
527 ret=iPluginChain.Append(aPlugin);
534 return(KErrNotFound);
537 ret=iPluginChain.Append(aPlugin);
540 ret=iPluginChain.Insert(aPlugin,aPos);
546 Looks for a plugin in the chain
548 TInt FsPluginManager::IsInChain(TInt aUPos,TInt aPos, TInt aDrive, CFsPluginFactory* aPluginFactory)
550 TInt count= iPluginChain.Count();
552 if(aPos == KPluginAutoLocate)
554 for(TInt i=0;i<count;i++)
556 CFsPlugin* pP = iPluginChain[i];
557 if(aPluginFactory->SupportedDrives()&KPluginVersionTwo) //Version2
559 //If KPluginAutoAttach, then we're dismounted from all drives.
560 //If KPluginMountDriveZ, then check against 25 explicitly (cannot change aDrive:=Z as that==KPluginAutoAttach))
561 //If any other drive mounted.
562 if(aUPos == pP->iUniquePos && (aDrive==KPluginAutoAttach || (aDrive==KPluginMountDriveZ && pP->iMountedOn & (1<<EDriveZ)) || pP->iMountedOn & (1<<aDrive)))
567 if(aUPos == pP->iUniquePos && (aDrive==KPluginAutoAttach || pP->iMountedOn & (1<<aDrive)))
574 if(aPos+1>iPluginChain.Count())
575 return(KErrNotFound);
577 if(iPluginChain[aPos]->iUniquePos == aUPos && aDrive==iPluginChain[aPos]->Drive())
583 Finds a plugin by unique position
585 CFsPlugin* FsPluginManager::FindByUniquePosition(TInt aUniquePosition)
588 CFsPlugin* plugin = NULL;
589 TInt count= iPluginChain.Count();
590 for(TInt i=0;i<count;i++)
592 if(aUniquePosition == iPluginChain[i]->iUniquePos)
594 plugin = iPluginChain[i];
603 Create a connection to a plugin
605 CFsPluginConn* FsPluginManager::CreatePluginConnL(TInt aUniquePosition, TUint aClientId)
607 CFsPlugin* pP = FindByUniquePosition(aUniquePosition);
610 CFsPluginConn* pC = pP->NewPluginConnL();
611 CleanupStack::PushL(pC);
613 pC->iClientId = aClientId;
614 iPluginConns->AddL(pC, ETrue);
615 CleanupStack::Pop(pC);
619 User::Leave(KErrNotFound);
624 Create a plugin thread
625 Should only by called from main file server thread with plugin thread unavailable
627 TInt FsPluginManager::InitPlugin(CFsPlugin& aPlugin)
631 if(!aPlugin.iThreadP)
633 TRAP(err,aPlugin.iThreadP=CPluginThread::NewL(aPlugin));
638 aPlugin.iThreadId = aPlugin.iThreadP->StartL();
642 Cancels plugin requests
644 void FsPluginManager::CancelPlugin(CFsPlugin* aPlugin,CSessionFs* aSession)
646 aPlugin->iThreadP->CompleteSessionRequests(aSession,KErrCancel);
650 Gets number of plugins in the plugin stack
652 TInt FsPluginManager::ChainCount()
654 return(iPluginChain.Count());
658 * Returns a CFsPlugin* from aPos in the plugin chain.
660 * To be called whilst already holding the iChainLock.
662 * @returns (via parameter) CFsPlugin*& aPlugin
664 TInt FsPluginManager::Plugin(CFsPlugin*& aPlugin, TInt aPos)
666 if(aPos >= iPluginChain.Count() || aPos < 0)
669 aPlugin = iPluginChain[aPos];
676 void FsPluginManager::LockChain()
684 void FsPluginManager::UnlockChain()
690 Gets plugin conn from handle
692 CFsPluginConn* FsPluginManager::GetPluginConnFromHandle(CSessionFs* aSession, TInt aHandle)
694 return((CFsPluginConn*)(SessionObjectFromHandle(aHandle,iPluginConns->UniqueID(),aSession)));
698 Checks if the current thread is plugin conn's thread
700 TBool FsPluginManager::IsPluginConnThread(TThreadId tid, CFsPlugin* aPlugin)
702 iPluginConns->Lock();
703 TInt count = iPluginConns->Count();
706 CFsPluginConn* conn = (CFsPluginConn*)(*iPluginConns)[count];
707 if(conn->Plugin() == aPlugin)
709 if(conn->ClientId() == tid)
711 iPluginConns->Unlock();
716 iPluginConns->Unlock();
721 Dispatch a synchronous message
723 void FsPluginManager::DispatchSync(CFsRequest* aRequest)
725 __THRD_PRINT(_L("FsPluginManager::DispatchSync"));
726 if(!FsThreadManager::IsMainThread() && iScheduler)
728 iScheduler->Dispatch(aRequest);
736 void FsPluginManager::CompleteSessionRequests(CSessionFs* aSession, TInt aValue, CFsInternalRequest* aRequest)
738 * Complete outstanding requests for the specified session
741 __PRINT2(_L("FsPluginManager::CompleteSessionRequests(%08x, %d)"), aSession, aValue);
743 // Iterate through all plugins, cancelling outstanding session requests
744 aRequest->Set(CancelPluginOp, aSession);
746 FsPluginManager::LockChain();
747 TInt count = FsPluginManager::ChainCount();
749 for(i=0; i<count; i++)
751 CFsPlugin* plugin = NULL;
752 User::LeaveIfError(FsPluginManager::Plugin(plugin, i));
753 __ASSERT_DEBUG(plugin, User::Leave(KErrNotFound));
754 aRequest->iCurrentPlugin = plugin;
755 aRequest->Status() = KRequestPending;
756 aRequest->Dispatch();
757 //Cancel is delivered to the front of the request queue
758 //so hopefully this wont take too long.
759 FsPluginManager::UnlockChain();
760 User::WaitForRequest(aRequest->Status());
761 FsPluginManager::LockChain();
762 __ASSERT_ALWAYS(aRequest->Status().Int()==KErrNone||aRequest->Status().Int()==KErrCancel,Fault(ESessionDisconnectThread2));
763 count = FsPluginManager::ChainCount();
765 FsPluginManager::UnlockChain();
767 // RDebug::Print(_L("FsPluginManager::CompleteSessionRequests - CSRs"));
768 iScheduler->CompleteSessionRequests(aSession, aValue);