userlibandfileserver/fileserver/sfile/sf_plugin_man.cpp
changeset 43 96e5fb8b040d
equal deleted inserted replaced
-1:000000000000 43:96e5fb8b040d
       
     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".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // f32\sfile\sf_plugin.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include <e32std.h>
       
    19 #include "sf_std.h"
       
    20 #include "sf_plugin_priv.h"
       
    21 
       
    22 CFsObjectCon* FsPluginManager::iPluginFactories = NULL;
       
    23 CFsObjectCon* FsPluginManager::iPluginConns     = NULL;
       
    24 RFastLock FsPluginManager::iChainLock;
       
    25 RPointerArray<CFsPlugin> FsPluginManager::iPluginChain;
       
    26 CFsSyncMessageScheduler* FsPluginManager::iScheduler = NULL;
       
    27 
       
    28 TBool IsPagableDrive(TInt aDrive)
       
    29 	{
       
    30 	if(LocalDrives::IsValidDriveMapping(aDrive))
       
    31 		{
       
    32 		TLocalDriveCapsBuf capsBuf;	
       
    33 		if(!LocalDrives::IsProxyDrive(aDrive) && LocalDrives::GetLocalDrive(aDrive).Caps(capsBuf) && capsBuf().iDriveAtt & KDriveAttPageable)
       
    34 			{
       
    35 			return (TBool)ETrue;
       
    36 			}
       
    37 		}
       
    38 	return (TBool) EFalse;
       
    39 	}
       
    40 
       
    41 /*
       
    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.
       
    44 */
       
    45 TInt NonPagableDrivesMask(TInt aNonPagableDriveMask)
       
    46 	{
       
    47 	TInt driveMask = aNonPagableDriveMask;
       
    48 	for(TInt i = 0; i < KMaxDrives; i++)
       
    49 		{
       
    50 		//If we're interested in this drive
       
    51 		if((aNonPagableDriveMask & 1<<i) && IsPagableDrive(i)) 
       
    52 			{
       
    53 			driveMask ^= 1<<i; //remove this drive
       
    54 			}
       
    55 		}
       
    56 	return driveMask;
       
    57 	}
       
    58 
       
    59 TInt FsPluginManager::UpdateMountedDrive(CFsPlugin* aPlugin, CFsPluginFactory* aFactory,TInt aDrive)
       
    60 	{
       
    61 	if(aDrive==KPluginAutoAttach) //KPluginAutoAttach
       
    62 		{
       
    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);
       
    67 			}
       
    68 		else 
       
    69 			{ //Version 2 Plugin - Mount on what the plugin supports (except pagable drives)
       
    70 			aPlugin->iMountedOn = NonPagableDrivesMask((aFactory->SupportedDrives()&(~KPluginVersionTwo)));
       
    71 			}
       
    72 		
       
    73 		if(!(aPlugin->iMountedOn &(~KPluginVersionTwo))) 
       
    74 			{ //Are we mounted on anything?
       
    75 			return KErrNotSupported;
       
    76 			}
       
    77 		return KErrNone;
       
    78 		}
       
    79 	
       
    80 	// DriveZ special handling
       
    81 	if(aDrive==KPluginMountDriveZ)
       
    82 		aDrive = EDriveZ;
       
    83 	
       
    84 	//Mounting on a single drive
       
    85 	if(!IsPagableDrive(aDrive))
       
    86 		{
       
    87 		aPlugin->iMountedOn |= 1<<aDrive;
       
    88 		return KErrNone;
       
    89 		}
       
    90 
       
    91 	return KErrNotSupported;
       
    92 	}
       
    93 
       
    94 /**
       
    95 FsPluginManager::Initialise
       
    96 */
       
    97 void FsPluginManager::InitialiseL()
       
    98 	{
       
    99 	iPluginFactories = TheContainer->CreateL();
       
   100 	iPluginConns = TheContainer->CreateL();
       
   101 	iPluginChain.Reset();
       
   102 	User::LeaveIfError(iChainLock.CreateLocal());
       
   103 
       
   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();
       
   108 	iScheduler->RunL();
       
   109 	}
       
   110 
       
   111 /**
       
   112 FsPluginManager::MountPlugin
       
   113 */
       
   114 TInt FsPluginManager::MountPlugin(CFsPluginFactory& aPluginFactory, TInt aDrive, TInt aPos)
       
   115 	{
       
   116 	TInt uniquePosition = aPluginFactory.UniquePosition();
       
   117 	CFsPlugin* pP = NULL;
       
   118 	CFsPluginFactory* pF = &aPluginFactory;
       
   119 	
       
   120 	//Version1 plugins could either been mounted on 1 or all drives.
       
   121 	//This isn't particularily desirable.
       
   122 	// Thus -
       
   123 	//For version2 plugins:
       
   124 	//Check whether this plugin has already been mounted
       
   125 	pP = FindByUniquePosition(uniquePosition);
       
   126 	if(pP && (aPluginFactory.iSupportedDrives&KPluginVersionTwo))
       
   127 		{
       
   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);
       
   132 		}
       
   133 	
       
   134 	
       
   135 	TRAPD(err, pP = aPluginFactory.NewPluginL());
       
   136 	if(err != KErrNone)
       
   137 		{
       
   138 		if(pP)
       
   139 			pP->Close();
       
   140 		return err;
       
   141 		}
       
   142 
       
   143 	TFullName name = aPluginFactory.Name();
       
   144 	pP->SetName(&name);
       
   145 	pP->iUniquePos=aPluginFactory.UniquePosition();
       
   146 	pP->SetDrive(aDrive);
       
   147 	
       
   148 	//Set which drive(s?) this plugin is mounted on.
       
   149 	err = UpdateMountedDrive(pP,pF,aDrive);
       
   150 	if(err != KErrNone)
       
   151 		{
       
   152 		pP->Close();
       
   153 		return err;
       
   154 		}
       
   155 
       
   156 	LockChain();
       
   157 	err = InsertInPluginStack(pP,aPos);
       
   158 	UnlockChain();
       
   159 	if(err != KErrNone)
       
   160 		{
       
   161 		pP->Close();
       
   162 		return err;
       
   163 		}
       
   164 
       
   165 	err = InitPlugin(*pP);
       
   166 	if(err != KErrNone)
       
   167 		{
       
   168 		return err;
       
   169 		}
       
   170  	aPluginFactory.IncrementMounted();
       
   171 
       
   172 	return KErrNone;
       
   173 	}
       
   174 
       
   175 /**
       
   176 Dismounts a plugin
       
   177 
       
   178 Must be called with the plugin chain locked.
       
   179 */
       
   180 void FsPluginManager::DismountPlugin(CFsPluginFactory& aPluginFactory,TInt aPos)
       
   181 	{
       
   182 	CFsPlugin* plugin=iPluginChain[aPos];
       
   183 
       
   184 	if (plugin != NULL)
       
   185 		{
       
   186 		// Check if there is any requests for this plugin
       
   187 		// if so, deliver them to the next supporting plugin
       
   188 		TransferRequests(plugin->iThreadP);
       
   189 
       
   190 		plugin->iThreadP=NULL;
       
   191 		
       
   192 		//Remove the plugin from the chain
       
   193 		iPluginChain.Remove(aPos);
       
   194 		iPluginChain.Compress();
       
   195 
       
   196 	    //Close the plugin (destructed when CPluginThread is destructed).
       
   197  		plugin->Close();
       
   198 		plugin=NULL;
       
   199 		}
       
   200 	else
       
   201 		{
       
   202 		ASSERT(0);	// force panic in debug mode
       
   203 		}
       
   204 
       
   205 	aPluginFactory.DecrementMounted();
       
   206 	}
       
   207 
       
   208 /*
       
   209  * This will iterate through a plugins request queue and 
       
   210  * search for the first occurance it finds of a CancelPluginOp
       
   211  * request.
       
   212  */
       
   213 void FsPluginManager::GetNextCancelPluginOpRequest(CPluginThread* aPluginThread, CFsRequest*& aCancelPluginRequest)
       
   214     {
       
   215     __THRD_PRINT(_L("FsPluginManager::GetNextCancelPluginOpRequest"));
       
   216     
       
   217     TDblQueIter<CFsRequest> iter(aPluginThread->iList);
       
   218     CFsRequest* request = NULL;
       
   219 
       
   220     while((request=iter++)!=NULL)
       
   221         {
       
   222         if(request->Operation()->iFunction == KCancelPlugin)
       
   223             {
       
   224             aCancelPluginRequest = request;
       
   225             break;
       
   226             }
       
   227         }
       
   228     }
       
   229  
       
   230 
       
   231 
       
   232 
       
   233 
       
   234 /**
       
   235 Transfer any outstanding requests to next/previous plugin depending on
       
   236 if it is post filter or not
       
   237 
       
   238 Must be called with the plugin chain locked.
       
   239 Attains plugin-thread's listlock.
       
   240 */
       
   241 void FsPluginManager::TransferRequests(CPluginThread* aPluginThread)
       
   242 	{
       
   243 	aPluginThread->iListLock.Wait();
       
   244 	
       
   245 	__THRD_PRINT(_L("FsPluginManager::TransferRequests - moving requests"));
       
   246 	
       
   247 	/*
       
   248 	 * We are transferring requests up and down the chain
       
   249 	 * because this plugin is being removed.
       
   250 	 * 
       
   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. 
       
   257 	 * 
       
   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].
       
   262 	 * 
       
   263 	 * Therefore, we shall check whether there is a KCancelPlugin op in the 
       
   264 	 * chain first. 
       
   265      * If there is a cancelPluginOp in the chain, we will cancel of the requests 
       
   266      * that are associated with that session.
       
   267      * 
       
   268      * After that is out of the way we preserve the remaining requests for different sessions by
       
   269      * passing them on.
       
   270 	 */
       
   271 	if(!aPluginThread->iList.IsEmpty())
       
   272 	    {
       
   273 	    CFsRequest* cancelRequest = NULL;
       
   274 	    //For every CancelPluginOp 
       
   275 	    while(FsPluginManager::GetNextCancelPluginOpRequest(aPluginThread, cancelRequest), cancelRequest!=NULL)
       
   276 	        {
       
   277 	        RDebug::Print(_L("Transferring Plugin Requests - CancelPluginOp"));
       
   278 	        TDblQueIter<CFsRequest> iter(aPluginThread->iList);
       
   279 	        CFsRequest* request = NULL;
       
   280 	        //For every request
       
   281 	        while((request=iter++)!=NULL)
       
   282 	            {
       
   283 	            if(request->Session() == cancelRequest->Session() && request != cancelRequest)
       
   284 	                {
       
   285 	                request->iLink.Deque();
       
   286 	                request->Complete(KErrCancel);
       
   287 	                }
       
   288 	            }
       
   289 	        cancelRequest->iLink.Deque();
       
   290 	        cancelRequest->Complete(KErrNone);
       
   291 	        cancelRequest = NULL;
       
   292 	        }
       
   293 
       
   294 	    /*
       
   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.
       
   298 	     * 
       
   299 	     * ToDo: This next 'while' might be able to be replaced with a call to
       
   300 	     * DispatchToPlugin/DispatchToDrive instead.
       
   301 	     */
       
   302 	    while(!aPluginThread->iList.IsEmpty())
       
   303 	        {
       
   304 	        CFsRequest* pR=aPluginThread->iList.First();
       
   305 	        CFsMessageRequest& mR = *(CFsMessageRequest*) pR;
       
   306 	        pR->iLink.Deque();
       
   307 	        pR->iCurrentPlugin=NULL;
       
   308 
       
   309 	        if(pR->IsPluginSpecific())
       
   310 	            {
       
   311 	            pR->Complete(KErrCancel);
       
   312 	            continue;
       
   313 	            }
       
   314 
       
   315 	        if(pR->IsPostOperation())
       
   316 	            {
       
   317 	            //[set the plugin to] pass the request backwards in the chain
       
   318 	            PrevPlugin(pR->iCurrentPlugin, &mR, EFalse);
       
   319 	            }
       
   320 	        else //IsPreOperations
       
   321 	            {
       
   322 	            //[set the plugin to] pass the request forwards in the chain
       
   323 	            NextPlugin(pR->iCurrentPlugin, &mR, EFalse);
       
   324 	            }
       
   325 
       
   326 	        if(pR->iCurrentPlugin)
       
   327 	            {
       
   328 	            pR->iCurrentPlugin->iThreadP->DeliverBack(pR);
       
   329 	            }
       
   330 	        else
       
   331 	            {
       
   332 	            if(!pR->IsPostOperation() && (pR->DriveNumber()>=EDriveA && pR->DriveNumber()<=EDriveZ))
       
   333 	                {
       
   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;
       
   339 	                pT->DeliverBack(pR);
       
   340 	                }
       
   341 	            else
       
   342 	                {
       
   343 	                pR->Complete(KErrCancel);
       
   344 	                }
       
   345 	            }
       
   346 	        }
       
   347 	    }
       
   348 
       
   349 	aPluginThread->iExit = ETrue;
       
   350 	aPluginThread->iListLock.Signal();
       
   351 
       
   352 	__THRD_PRINT(_L("FsPluginManager::TransferRequests - all requests moved/cancelled"));
       
   353 	}
       
   354 
       
   355 /**
       
   356 Install a plugin factory
       
   357 */
       
   358 TInt FsPluginManager::InstallPluginFactory(CFsPluginFactory* aFactory,RLibrary aLib)
       
   359 	{
       
   360 	TInt r=aFactory->Install();
       
   361 	__PRINT1TEMP(_L("InstallPluginFactory %S"),aFactory->Name());
       
   362 	if (r==KErrNone)
       
   363 		{TRAP(r,iPluginFactories->AddL(aFactory,ETrue))}
       
   364 	if (r!=KErrNone)
       
   365 		aFactory->Remove();
       
   366 	if (r==KErrNone)
       
   367 		aFactory->SetLibrary(aLib);
       
   368 	else
       
   369 		aFactory->Close();
       
   370 	return(r);
       
   371 	}
       
   372 
       
   373 /**
       
   374 Find a plugin factory by name
       
   375 */
       
   376 CFsPluginFactory* FsPluginManager::GetPluginFactory(const TDesC& aName)
       
   377 	{
       
   378 
       
   379 	TInt h=0;
       
   380 	TInt r=iPluginFactories->FindByName(h,aName);
       
   381 	if (r!=KErrNone)
       
   382 		return(NULL);
       
   383 	return((CFsPluginFactory*)iPluginFactories->At(h));
       
   384 	}
       
   385 
       
   386 /**
       
   387 Find the next plugin that supports the operation
       
   388 
       
   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.
       
   393                  
       
   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.
       
   396 
       
   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)
       
   400 */
       
   401 TInt FsPluginManager::NextPlugin(CFsPlugin*& aPlugin, CFsMessageRequest* aMsgRequest,TBool aLock, TBool aCheckCurrentOperation)
       
   402 	{
       
   403 	if(aMsgRequest->DirectToDrive())
       
   404 		{
       
   405 		aPlugin = NULL;
       
   406 		return KErrNotFound;
       
   407 		}
       
   408 
       
   409 	TInt start;
       
   410 	TInt function = aMsgRequest->Operation()->Function();
       
   411 	TInt drive = aMsgRequest->DriveNumber();
       
   412 
       
   413 	if(aLock)
       
   414 	    LockChain();
       
   415 	
       
   416 	//the plugin chain lock must be held by this point.
       
   417 	TInt count = iPluginChain.Count();
       
   418 
       
   419 	if(aPlugin == NULL)
       
   420 		start=0;
       
   421 	else
       
   422 		start = iPluginChain.Find(aPlugin)+1;
       
   423 
       
   424 	if(start!=KErrNotFound)
       
   425 		{
       
   426 		for(TInt i=start;i<count;i++)
       
   427 			{
       
   428 			if(!aCheckCurrentOperation || iPluginChain[i]->IsRegistered(function, CFsPlugin::EPreIntercept))
       
   429 				{
       
   430 				if((function == EFsDismountPlugin) || (iPluginChain[i]->IsMounted(drive))) 
       
   431 					{
       
   432 
       
   433 					aPlugin = iPluginChain[i];
       
   434 					if(aLock)
       
   435 					    UnlockChain();
       
   436 					return KErrNone;
       
   437 					}
       
   438 				}
       
   439 			}
       
   440 		}
       
   441 	aPlugin = NULL;
       
   442 	if(aLock)
       
   443 	    UnlockChain();
       
   444 	return KErrNotFound;
       
   445 	}
       
   446 
       
   447 /**
       
   448 Find the next plugin that supports the operation
       
   449 
       
   450 @see FsPluginManager::NextPlugin
       
   451 */
       
   452 TInt FsPluginManager::PrevPlugin(CFsPlugin*& aPlugin, CFsMessageRequest* aMsgRequest, TBool aLock)
       
   453 	{
       
   454 	if(aMsgRequest->DirectToDrive() && (aMsgRequest->CurrentOperationPtr() != NULL))
       
   455 		{
       
   456 		aPlugin = NULL;
       
   457 		return KErrNotFound;
       
   458 		}
       
   459 
       
   460 	TInt start;
       
   461 	TInt function = aMsgRequest->Operation()->Function();
       
   462 	TInt drive = aMsgRequest->DriveNumber();
       
   463 
       
   464 	if(aLock)
       
   465 	    LockChain();
       
   466 	
       
   467 	//the plugin chain lock must be held by this point.
       
   468 	TInt count= iPluginChain.Count();
       
   469 
       
   470 	if(aPlugin == NULL)
       
   471 		start = count-1;
       
   472 	else
       
   473 		start = iPluginChain.Find(aPlugin)-1;
       
   474 
       
   475 	if(start!=KErrNotFound)
       
   476 		{
       
   477 		for(TInt i=start;i>=0;i--)
       
   478 			{
       
   479 			CFsPlugin* owner = aMsgRequest->iOwnerPlugin;
       
   480 			if(owner == iPluginChain[i])
       
   481 				break;
       
   482 
       
   483 			if(iPluginChain[i]->IsRegistered(function, CFsPlugin::EPostIntercept))
       
   484 				{
       
   485 				if((function == EFsDismountPlugin) || (iPluginChain[i]->IsMounted(drive))) 
       
   486 					{
       
   487 
       
   488 					aPlugin = iPluginChain[i];
       
   489 					if(aLock)
       
   490 					    UnlockChain();
       
   491 					return KErrNone;
       
   492 					}
       
   493 				}
       
   494 			}
       
   495 		}
       
   496 	aPlugin = NULL;
       
   497 	if(aLock)
       
   498 	    UnlockChain();
       
   499 	return KErrNotFound;
       
   500 	}
       
   501 /**
       
   502 Inserts the plugin in the stack (chain)
       
   503 
       
   504 if aPos absolute postion, it simply inserts it
       
   505 if aPos unique position, it walks through chain and checks the unique positions
       
   506 */
       
   507 TInt FsPluginManager::InsertInPluginStack(CFsPlugin*& aPlugin,TInt aPos)
       
   508 	{
       
   509 	TInt ret=KErrNone;
       
   510 	TInt count= iPluginChain.Count();
       
   511 	if(aPos == KPluginAutoLocate)
       
   512 		{
       
   513 		TInt uPos= aPlugin->iUniquePos;
       
   514 		for(TInt i=0;i<count;i++)
       
   515 			{
       
   516 			if(uPos == iPluginChain[i]->iUniquePos)
       
   517 				{
       
   518 				return KErrInUse;
       
   519 				}
       
   520 
       
   521 			if(uPos < iPluginChain[i]->iUniquePos)
       
   522 				{
       
   523 				ret=iPluginChain.Insert(aPlugin,i);
       
   524 				return ret;
       
   525 				}
       
   526 			}
       
   527 		ret=iPluginChain.Append(aPlugin);
       
   528 		}
       
   529 	else
       
   530 		{
       
   531 		// Absolute position
       
   532 
       
   533 		if(aPos > count)
       
   534 			return(KErrNotFound);
       
   535 		if(aPos == count)
       
   536 			{
       
   537 			ret=iPluginChain.Append(aPlugin);
       
   538 			return ret;
       
   539 			}
       
   540 		ret=iPluginChain.Insert(aPlugin,aPos);
       
   541 		}
       
   542 	return ret;
       
   543 	}
       
   544 
       
   545 /**
       
   546 Looks for a plugin in the chain
       
   547 */
       
   548 TInt FsPluginManager::IsInChain(TInt aUPos,TInt aPos, TInt aDrive, CFsPluginFactory* aPluginFactory)
       
   549 	{
       
   550 	TInt count= iPluginChain.Count();
       
   551 	
       
   552 	if(aPos == KPluginAutoLocate)
       
   553 		{
       
   554 		for(TInt i=0;i<count;i++)
       
   555 			{
       
   556 			CFsPlugin* pP = iPluginChain[i];
       
   557 			if(aPluginFactory->SupportedDrives()&KPluginVersionTwo) //Version2
       
   558 				{
       
   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)))
       
   563 					return i;
       
   564 				}
       
   565 			else //version1
       
   566 				{
       
   567 				if(aUPos == pP->iUniquePos && (aDrive==KPluginAutoAttach || pP->iMountedOn & (1<<aDrive)))
       
   568 					return i;
       
   569 				}
       
   570 			}
       
   571 		return KErrNotFound;
       
   572 		}
       
   573 
       
   574 	if(aPos+1>iPluginChain.Count())
       
   575 		return(KErrNotFound);
       
   576 
       
   577 	if(iPluginChain[aPos]->iUniquePos == aUPos && aDrive==iPluginChain[aPos]->Drive())
       
   578 		return aPos;
       
   579 	return KErrNotFound;
       
   580 	}
       
   581 
       
   582 /**
       
   583 Finds a plugin by unique position
       
   584 */
       
   585 CFsPlugin* FsPluginManager::FindByUniquePosition(TInt aUniquePosition)
       
   586 	{
       
   587 	LockChain();
       
   588 	CFsPlugin* plugin = NULL;
       
   589 	TInt count= iPluginChain.Count();
       
   590 	for(TInt i=0;i<count;i++)
       
   591 		{
       
   592 		if(aUniquePosition == iPluginChain[i]->iUniquePos)
       
   593 			{
       
   594 			plugin = iPluginChain[i];
       
   595 			break;
       
   596 			}
       
   597 		}
       
   598 	UnlockChain();
       
   599 	return plugin;
       
   600 	}
       
   601 
       
   602 /**
       
   603 Create a connection to a plugin
       
   604 */
       
   605 CFsPluginConn* FsPluginManager::CreatePluginConnL(TInt aUniquePosition, TUint aClientId)
       
   606 	{
       
   607 	CFsPlugin* pP = FindByUniquePosition(aUniquePosition);
       
   608 	if(pP != NULL)
       
   609 		{
       
   610 		CFsPluginConn* pC = pP->NewPluginConnL();
       
   611 		CleanupStack::PushL(pC);
       
   612 		pC->iPluginP = pP;
       
   613 		pC->iClientId = aClientId;
       
   614 		iPluginConns->AddL(pC, ETrue);
       
   615 		CleanupStack::Pop(pC);
       
   616 		return pC;
       
   617 		}
       
   618 
       
   619 	User::Leave(KErrNotFound);
       
   620 	return NULL;
       
   621 	}
       
   622 
       
   623 /**
       
   624 Create a plugin thread
       
   625 Should only by called from main file server thread with plugin thread unavailable
       
   626 */
       
   627 TInt FsPluginManager::InitPlugin(CFsPlugin& aPlugin)
       
   628 	{
       
   629 	TInt err = KErrNone;
       
   630 
       
   631 	if(!aPlugin.iThreadP)
       
   632 		{
       
   633 		TRAP(err,aPlugin.iThreadP=CPluginThread::NewL(aPlugin));
       
   634 		if(err!=KErrNone)
       
   635 			return err;
       
   636 		}
       
   637 
       
   638 	aPlugin.iThreadId = aPlugin.iThreadP->StartL();
       
   639 	return err;
       
   640 	}
       
   641 /**
       
   642 Cancels plugin requests
       
   643 */
       
   644 void FsPluginManager::CancelPlugin(CFsPlugin* aPlugin,CSessionFs* aSession)
       
   645 	{
       
   646 	aPlugin->iThreadP->CompleteSessionRequests(aSession,KErrCancel);
       
   647 	}
       
   648 
       
   649 /**
       
   650 Gets number of plugins in the plugin stack
       
   651 */
       
   652 TInt FsPluginManager::ChainCount()
       
   653 	{
       
   654 	return(iPluginChain.Count());
       
   655 	}
       
   656 
       
   657 /**
       
   658  * Returns a CFsPlugin* from aPos in the plugin chain.
       
   659  * 
       
   660  * To be called whilst already holding the iChainLock.
       
   661  * 
       
   662  * @returns (via parameter) CFsPlugin*& aPlugin
       
   663 */
       
   664 TInt FsPluginManager::Plugin(CFsPlugin*& aPlugin, TInt aPos)
       
   665 	{
       
   666 	if(aPos >= iPluginChain.Count() || aPos < 0)
       
   667 	    return KErrNotFound;
       
   668 	
       
   669 	aPlugin = iPluginChain[aPos];
       
   670 	return KErrNone;
       
   671 	}
       
   672 
       
   673 /**
       
   674 Locks the chain
       
   675 */
       
   676 void FsPluginManager::LockChain()
       
   677 	{
       
   678 	iChainLock.Wait();
       
   679 	}
       
   680 
       
   681 /**
       
   682 Unlocks the chain
       
   683 */
       
   684 void FsPluginManager::UnlockChain()
       
   685 	{
       
   686 	iChainLock.Signal();
       
   687 	}
       
   688 
       
   689 /**
       
   690 Gets plugin conn from handle
       
   691 */
       
   692 CFsPluginConn* FsPluginManager::GetPluginConnFromHandle(CSessionFs* aSession, TInt aHandle)
       
   693 	{
       
   694 	return((CFsPluginConn*)(SessionObjectFromHandle(aHandle,iPluginConns->UniqueID(),aSession)));
       
   695 	}
       
   696 
       
   697 /**
       
   698 Checks if the current thread is plugin conn's thread
       
   699 */
       
   700 TBool FsPluginManager::IsPluginConnThread(TThreadId tid, CFsPlugin* aPlugin)
       
   701 	{
       
   702 	iPluginConns->Lock();
       
   703 	TInt count = iPluginConns->Count();
       
   704 	while(count--)
       
   705 		{
       
   706 		CFsPluginConn* conn = (CFsPluginConn*)(*iPluginConns)[count];
       
   707 		if(conn->Plugin() == aPlugin)
       
   708 			{
       
   709 			if(conn->ClientId() == tid)
       
   710 				{
       
   711 				iPluginConns->Unlock();
       
   712 				return ETrue;
       
   713 				}
       
   714 			}
       
   715 		}
       
   716 	iPluginConns->Unlock();
       
   717 	return EFalse;
       
   718 	}
       
   719 
       
   720 /**
       
   721 Dispatch a synchronous message
       
   722 */
       
   723 void FsPluginManager::DispatchSync(CFsRequest* aRequest)
       
   724 	{
       
   725 	__THRD_PRINT(_L("FsPluginManager::DispatchSync"));
       
   726 	if(!FsThreadManager::IsMainThread() && iScheduler)
       
   727 		{
       
   728 		iScheduler->Dispatch(aRequest);
       
   729 		}
       
   730 	else
       
   731 		{
       
   732 		aRequest->Process();
       
   733 		}
       
   734 	}
       
   735 
       
   736 void FsPluginManager::CompleteSessionRequests(CSessionFs* aSession, TInt aValue, CFsInternalRequest* aRequest)
       
   737 /**
       
   738  * Complete outstanding requests for the specified session
       
   739  */
       
   740 	{
       
   741 	__PRINT2(_L("FsPluginManager::CompleteSessionRequests(%08x, %d)"), aSession, aValue);
       
   742 
       
   743 	// Iterate through all plugins, cancelling outstanding session requests
       
   744 	aRequest->Set(CancelPluginOp, aSession);
       
   745 
       
   746 	FsPluginManager::LockChain();
       
   747 	TInt count = FsPluginManager::ChainCount();
       
   748 	TInt i;
       
   749 	for(i=0; i<count; i++)
       
   750 	    {
       
   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();
       
   764 	    }
       
   765 	FsPluginManager::UnlockChain();
       
   766 	
       
   767 //	RDebug::Print(_L("FsPluginManager::CompleteSessionRequests - CSRs"));
       
   768 	iScheduler->CompleteSessionRequests(aSession, aValue);
       
   769 	}
       
   770 
       
   771