os/kernelhwsrv/userlibandfileserver/fileserver/sfile/sf_request.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
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".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // f32\sfile\sf_request.cpp
    15 // 
    16 //
    17 
    18 #include "sf_std.h"
    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	
    23 
    24 
    25 TParse dummyP;
    26 RMessage2 dummyM;
    27 
    28 CFsClientMessageRequest* RequestAllocator::iFreeHead;				
    29 CFsClientMessageRequest* RequestAllocator::iCloseHead;
    30 TInt RequestAllocator::iAllocNum;
    31 TInt RequestAllocator::iAllocNumOperation;
    32 TMsgOperation* RequestAllocator::iFreeHeadSupOp;
    33 
    34 #if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
    35 TInt RequestAllocator::iAllocated;
    36 #endif
    37 RFastLock RequestAllocator::iCacheLock;
    38 
    39 void RequestAllocator::Initialise()
    40 	{	
    41 	iFreeHead=NULL;  
    42 	iCloseHead=NULL; 
    43 	iAllocNum=0; 
    44 #if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
    45 	iAllocated=0;
    46 #endif
    47 	iAllocNumOperation=0;
    48 	iFreeHeadSupOp=NULL;
    49 	}
    50 
    51 TInt RequestAllocator::AllocRequest(TInt aNum)
    52 //
    53 //	Allocates a group of request objects
    54 //
    55 	{
    56     TInt i;
    57 	if(iAllocNum < KMaxRequestAllocated)
    58 		{
    59 		__CACHE_PRINT(_L("RequestAllocator::AllocRequest() Not reached the limit"));
    60 		CFsClientMessageRequest* list;
    61 		CFsClientMessageRequest* start;
    62 		list = new CFsClientMessageRequest[KAllocReqBlock];
    63 		start = list;
    64 		if(!list)
    65 			return KErrNoMemory;
    66 		
    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++)
    70 			{
    71 			CFsClientMessageRequest* request = &list[j];
    72 			new(request) CFsClientMessageRequest();
    73 			}
    74 
    75 		iAllocNum += KAllocReqBlock;
    76 		CFsClientMessageRequest* last;
    77 		for(i=1;i<KAllocReqBlock;i++)
    78 			{
    79 			last = list;
    80 			list++;
    81 			last->iNext = list;
    82 			}
    83 		list->iNext = iFreeHead;
    84 		iFreeHead = start;
    85 		return KErrNone;
    86 		}
    87 	else
    88 		{
    89 		__CACHE_PRINT1(_L("RequestAllocator::AllocRequest() Limit exceeded Count = %d"),aNum);
    90 		CFsClientMessageRequest* request;
    91 		for(i=0;i<aNum;i++)
    92 			{
    93 			request=new CFsClientMessageRequest;
    94 			if(!request)
    95 				return KErrNoMemory;
    96 #if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
    97 			iAllocated++;
    98 #endif
    99 			request->SetAllocated();
   100 			request->iNext=iFreeHead;
   101 			iFreeHead=request;
   102 			}
   103 		return KErrNone;
   104 		}
   105 	}
   106 
   107 void RequestAllocator::FreeRequest(CFsClientMessageRequest* aRequest)
   108 //
   109 //free request 
   110 //
   111 	{
   112 	__CACHE_PRINT1(_L("PLUGIN: RequestAllocator::FreeRequest for %x"), aRequest);
   113 	if(aRequest->IsAllocated())
   114 		{
   115 		__CACHE_PRINT(_L("RequestAllocator::FreeRequest() Allocated request"));
   116 		delete(aRequest);
   117 #if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
   118 		iAllocated--;
   119 #endif
   120 		return;
   121 		}
   122 	
   123 	__CACHE_PRINT(_L("RequestAllocator::FreeRequest() returning to free list"));
   124 	iCacheLock.Wait();
   125 	aRequest->iNext = iFreeHead;
   126 	iFreeHead=aRequest;
   127 	aRequest->SetSubstedDrive(NULL);
   128 	iCacheLock.Signal();
   129 	}
   130 
   131 void RequestAllocator::OpenSubFailed(CSessionFs* aSession)
   132 //
   133 //	Move requst from closed list to free list
   134 //
   135 	{
   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)
   139 		{
   140 		return;
   141 		}
   142 	iCacheLock.Wait();
   143 	CFsClientMessageRequest* rp = iCloseHead;
   144 	iCloseHead = rp->iNext;
   145 	
   146 	// dec the number of closed requests owned by this session
   147 	aSession->CloseRequestCountDec();
   148 
   149 	rp->iNext = NULL;
   150 	if(rp->IsAllocated())
   151 		{
   152 		__CACHE_PRINT(_L("RequestAllocator::OpenSubFailed() Allocated request"));
   153 		delete(rp);
   154 #if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
   155 		iAllocated--;
   156 #endif
   157 		}
   158 	else
   159 		{
   160 		__CACHE_PRINT(_L("RequestAllocator::OpenSubFailed()"));
   161 		if(iFreeHead)
   162 			{
   163 			rp->iNext = iFreeHead;
   164 			}
   165 		else
   166 			{
   167 			rp->iNext = NULL;
   168 			}
   169 
   170 		iFreeHead = rp;		
   171 		}
   172 	iCacheLock.Signal();
   173 	}
   174 
   175 TInt RequestAllocator::GetMessageRequest(const TOperation& aOperation,const RMessage2& aMessage,CFsClientMessageRequest* &aRequest)
   176 //
   177 //	tries to get a pre allocated message from the cache. Failing that allocates one indivisualy 
   178 //	
   179 	{
   180 	if(aOperation.IsOpenSubSess())
   181 		{
   182 		__CACHE_PRINT(_L("++RequestAllocator::GetMessageRequest() Open sub-sess"));
   183 		iCacheLock.Wait();
   184 		if(iFreeHead == NULL || iFreeHead->iNext == NULL)
   185 			{
   186 			if(AllocRequest(2)!= KErrNone)
   187 				{
   188 				iCacheLock.Signal();
   189 				return KErrNoMemory;
   190 				}
   191 			}
   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
   194 
   195 		aRequest->iNext->iNext = NULL;				//seperate our request and close from free list
   196 		CFsClientMessageRequest* CRp = aRequest->iNext;
   197 		aRequest->iNext = NULL;
   198 		if(iCloseHead)
   199 			{
   200 			CRp->iNext = iCloseHead;		//set second one as a reserved (tail) close request
   201 			iCloseHead = CRp;
   202 			}
   203 		else
   204 			iCloseHead = CRp;
   205 		
   206 		((CSessionFs*) aMessage.Session())->CloseRequestCountInc();
   207 		}
   208 	else if(aOperation.IsCloseSubSess())
   209 		{
   210 		__CACHE_PRINT(_L("++RequestAllocator::GetMessageRequest() Close sub-sess"));
   211 
   212 		CFsObject* pO = SessionObjectFromHandle(aMessage.Int3(),0,reinterpret_cast<CSessionFs*>(aMessage.Session()));
   213 		if(!pO)
   214 			return KErrBadHandle;
   215 
   216 		CObjPromotion* pm = (CObjPromotion*)pO;
   217 		TInt function = aMessage.Function();
   218 		switch(function & KIpcFunctionMask)
   219 			{
   220 			case EFsFormatSubClose:
   221 				{
   222 				if(pm->UniqueID() != Formats->UniqueID())
   223 					{
   224 					return KErrBadHandle;
   225 					}
   226 				break;
   227 				}
   228 			case EFsDirSubClose:
   229 				{
   230 				if(pm->UniqueID() != Dirs->UniqueID())
   231 					{
   232 					return KErrBadHandle;
   233 					}
   234 				break;
   235 				}
   236 			case EFsFileSubClose:
   237 				{
   238 				if(pm->UniqueID() != FileShares->UniqueID())
   239 					{
   240 					return KErrBadHandle;
   241 					}
   242 				break;
   243 				}
   244 			case EFsRawSubClose:
   245 				{
   246 				if(pm->UniqueID() != RawDisks->UniqueID())
   247 					{
   248 					return KErrBadHandle;
   249 					}
   250 				break;
   251 				}
   252 			case EFsPluginSubClose:
   253 				{
   254 				if(pm->UniqueID() != FsPluginManager::iPluginConns->UniqueID())
   255 					{
   256 					return KErrBadHandle;
   257 					}
   258 				break;
   259 				}
   260 #ifdef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION					
   261 			case EFsNotificationSubClose:
   262 				{
   263 				if(pm->UniqueID() != FsNotificationManager::iNotifyRequests->UniqueID())
   264 					{
   265 					return KErrBadHandle;
   266 					}
   267 				break;
   268 				}
   269 #endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION					
   270 			default:
   271 				Fault(ECloseSubBadMessage);
   272 			}
   273 
   274 		iCacheLock.Wait();
   275 		aRequest = iCloseHead;
   276 		iCloseHead = aRequest->iNext;
   277 		((CSessionFs*) aMessage.Session())->CloseRequestCountDec();
   278 		aRequest->iNext = NULL;
   279 
   280 		if((function & KIpcFunctionMask)!= EFsPluginSubClose &&
   281 			(function & KIpcFunctionMask)!= EFsNotificationSubClose)
   282 			{
   283 			aRequest->SetDrive(&TheDrives[((CFsDispatchObject*)pO)->DriveNumber()]);
   284 			}
   285 
   286 		aRequest->SetScratchValue((TUint)pO);
   287 		}
   288 	else
   289 		{
   290 		__CACHE_PRINT(_L("++RequestAllocator::GetMessageRequest() "));
   291 		iCacheLock.Wait();
   292 		if(!iFreeHead)
   293 			{
   294 			if(AllocRequest(1) != KErrNone)
   295 				{
   296 				iCacheLock.Signal();
   297 				return KErrNoMemory; 
   298 				}
   299 			}
   300 		aRequest = iFreeHead;						
   301 		iFreeHead = aRequest->iNext;
   302 		aRequest->iNext= NULL;
   303 		}
   304 
   305 	aRequest->Init();
   306 
   307 	iCacheLock.Signal();
   308 
   309 	// pre-allocate any TParse objects needed by this request
   310 	if (aRequest->AllocParseObjects(aOperation) != KErrNone)
   311 		{
   312 		aRequest->Free();
   313 		return KErrNoMemory; 
   314 		}
   315 
   316 	__CACHE_PRINT1(_L("--RequestAllocator::GetMessageRequest() allocated %08x"), aRequest);
   317 
   318 	return KErrNone;
   319 	}	
   320 
   321 
   322 #if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
   323 TInt RequestAllocator::CloseCount()
   324 	{TInt count=0;
   325 	CFsClientMessageRequest* list=iCloseHead;
   326 	while(list!=NULL)
   327 		{
   328 		count++;
   329 		list=list->iNext;
   330 		}
   331 	return(count);
   332 	} 
   333 TInt RequestAllocator::FreeCount()
   334 	{
   335 	TInt count=0;
   336 	CFsClientMessageRequest* list=iFreeHead;
   337 	while(list!=NULL)
   338 		{
   339 		count++;
   340 		list=list->iNext;
   341 		}
   342 	return(count);}
   343 #endif
   344 
   345 TInt RequestAllocator::AllocOperation()
   346 //
   347 //	Allocates a group of TMsgOperation objects
   348 //
   349 // Must be called with iCacheLock held
   350 	{
   351     TInt i;
   352 	if(iAllocNumOperation < KMaxOperationAllocated)
   353 		{
   354 		__CACHE_PRINT(_L("RequestAllocator::AllocOperation() Not reached the limit"));
   355 		TMsgOperation* list;
   356 		TMsgOperation* start;
   357 		list = new TMsgOperation[KAllocReqBlock];
   358 		start = list;
   359 		if(!list)
   360 			return KErrNoMemory;
   361 		
   362 		for(TInt j=0; j<KAllocReqBlock; j++)
   363 			{
   364 			TMsgOperation* request = &list[j];
   365 			request->iIsAllocated = EFalse;
   366 			}
   367 
   368 		iAllocNumOperation += KAllocReqBlock;
   369 		TMsgOperation* last;
   370 		for(i=1;i<KAllocReqBlock;i++)
   371 			{
   372 			last = list;
   373 			list++;
   374 			last->iNext = list;
   375 			}
   376 		list->iNext = iFreeHeadSupOp;
   377 		iFreeHeadSupOp = start;
   378 		return KErrNone;
   379 		}
   380 	else
   381 		{
   382 		__CACHE_PRINT(_L("RequestAllocator::AllocOperation() Limit exceeded"));
   383 		TMsgOperation* request;
   384 
   385 		request=new TMsgOperation;
   386 		if(!request)
   387 			return KErrNoMemory;
   388 #if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
   389 		iAllocated++;
   390 #endif
   391 		request->iIsAllocated = ETrue;
   392 		request->iNext=iFreeHeadSupOp;
   393 		iFreeHeadSupOp=request;
   394 
   395 		return KErrNone;
   396 		}
   397 	}
   398 TInt RequestAllocator::GetOperation(TMsgOperation* &aOperation)
   399 //
   400 //	tries to get a pre allocated subop from the cache. Failing that allocates one individualy 
   401 //	
   402 	{
   403 
   404 	__CACHE_PRINT(_L("RequestAllocator::GetOperation() "));
   405 	iCacheLock.Wait();
   406 	if(!iFreeHeadSupOp)
   407 		{
   408 		if(AllocOperation() != KErrNone)
   409 			{
   410 			iCacheLock.Signal();
   411 			return KErrNoMemory; 
   412 			}
   413 		}
   414 	aOperation = iFreeHeadSupOp;						
   415 	iFreeHeadSupOp = aOperation->iNext;
   416 	aOperation->iNext = aOperation->iPrev = NULL;
   417 
   418 	iCacheLock.Signal();
   419 	return KErrNone;
   420 	}	
   421 
   422 void RequestAllocator::FreeOperation(TMsgOperation* aOperation)
   423 //
   424 // free Operation
   425 //
   426 	{
   427 	if(aOperation->iIsAllocated)
   428 		{
   429 		__CACHE_PRINT(_L("RequestAllocator::FreeOperation() Allocated subop"));
   430 		delete(aOperation);
   431 #if defined(_USE_CONTROLIO) || defined(_DEBUG) || defined(_DEBUG_RELEASE)
   432 		iAllocated--;
   433 #endif
   434 		return;
   435 		}
   436 	
   437 	__CACHE_PRINT(_L("RequestAllocator::FreeOperation() returning to free list"));
   438 	iCacheLock.Wait();
   439 	aOperation->iNext = iFreeHeadSupOp;	// NB backward link only used when request in in use
   440 	iFreeHeadSupOp = aOperation;
   441 
   442 	iCacheLock.Signal();
   443 	}
   444 
   445 
   446 CFsRequest::CFsRequest()
   447 //
   448 //
   449 //
   450 	: iOperation(NULL),iDriveNumber(KDriveInvalid)
   451 	{}
   452 
   453 CFsRequest::~CFsRequest()
   454 //
   455 //
   456 //
   457 	{}
   458 
   459 void CFsRequest::Set(const TOperation& aOperation,CSessionFs* aSession)
   460 //
   461 //
   462 //
   463 	{
   464 
   465 	SetState(EReqStateInitialise);
   466 
   467 	iOperation     = const_cast<TOperation*>(&aOperation);
   468 	iSession       = aSession;
   469 	iIsCompleted   = aOperation.IsCompleted();
   470 	iError         = KErrNone;
   471 	iDriveNumber   = KDriveInvalid;
   472 	iCurrentPlugin = NULL;
   473 	iOwnerPlugin   = NULL;
   474 	iDirectToDrive = EFalse;
   475 	iClientThreadId= 0;
   476 	iFlags &= ~(EFreeChanged | EPostInterceptEnabled | EPostOperation | EFsObjectOpen);
   477 	iScratchValue = 0;
   478 	}
   479 
   480 void CFsRequest::Set(CSessionFs* aSession)
   481 //
   482 //
   483 //
   484 	{
   485 	__ASSERT_DEBUG(iOperation,Fault(EBaseRequestSet1));
   486 
   487 	SetState(EReqStateInitialise);
   488 
   489 	iSession       = aSession;
   490 	iIsCompleted   = iOperation->IsCompleted();
   491 	iError         = KErrNone;
   492 	iDriveNumber   = KDriveInvalid;
   493 	iCurrentPlugin = NULL;
   494 	iOwnerPlugin   = NULL;
   495 	iDirectToDrive = EFalse;
   496 	iClientThreadId= 0;
   497 	iFlags &= ~(EFreeChanged | EPostInterceptEnabled | EPostOperation | EFsObjectOpen);
   498 	iScratchValue = 0;
   499 	}
   500 
   501 
   502 TParse& CFsRequest::Src()
   503 //
   504 //
   505 //
   506 	{
   507 	Fault(EBaseRequestSrc);
   508 	return(dummyP);
   509 	}
   510 
   511 TParse& CFsRequest::Dest()
   512 //
   513 //
   514 //
   515 	{
   516 	Fault(EBaseRequestDest);
   517 	return(dummyP);
   518 	}
   519 
   520 TDrive* CFsRequest::Drive()
   521 //
   522 //
   523 //
   524 	{
   525 	Fault(EBaseRequestDrive);
   526 	return(NULL);
   527 	}
   528 
   529 TDrive* CFsRequest::SubstedDrive()
   530 //
   531 //
   532 //
   533 	{
   534 	Fault(EBaseRequestSubstedDrive);
   535 	return(NULL);
   536 	}
   537 
   538 void CFsRequest::SetDrive(TDrive* /*aDrive*/)
   539 //
   540 //
   541 //
   542 	{
   543 	Fault(EBaseRequestSetDrive);
   544 	}
   545 
   546 void CFsRequest::SetSubstedDrive(TDrive* /*aDrive*/)
   547 //
   548 //
   549 //
   550 	{
   551 	Fault(EBaseRequestSetSubstedDrive);
   552 	}
   553 
   554 TInt CFsRequest::GetSlot(TFsPluginRequest::TF32ArgType aType)
   555 	{
   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;
   560 	
   561 	return(-1);
   562 	}
   563 
   564 
   565 TBool CFsMessageRequest::IsNotifierSpecific() const
   566 	{
   567 #ifndef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
   568 	return EFalse;
   569 #else
   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
   579 	}
   580 
   581 
   582 TBool CFsMessageRequest::IsNotifierSupported() const
   583 	{
   584 #ifndef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
   585 	return EFalse;
   586 #else
   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
   610 	}
   611 
   612 
   613 TInt CFsRequest::Read(TFsPluginRequest::TF32ArgType aType, TInt& aVal)
   614 	{
   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; }
   619 	
   620 	return KErrNotSupported;
   621 	}
   622 
   623 
   624 TInt CFsRequest::Read(TFsPluginRequest::TF32ArgType aType, TUint& aVal)
   625 	{
   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; }
   630 	
   631 	return KErrNotSupported;
   632 	}
   633 
   634 TInt CFsRequest::Read(TFsPluginRequest::TF32ArgType aType, TInt64& aVal)
   635 	{
   636 	TPckg<TInt64> pkVal(aVal);
   637 	// EFsFileLock, EFsFileUnLock, EFsFileSeek and EFsFileSetSize need special treatment
   638 	if(iOperation->Arg(0) == aType)
   639 		{
   640 		if((iOperation->Function()==EFsFileLock)   ||
   641 		   (iOperation->Function()==EFsFileUnLock)   )
   642 			{
   643 			if(IsDescData(KMsgPtr0))
   644 				Read(KMsgPtr0,pkVal);
   645 			else
   646 				aVal = MAKE_TINT64(0, Message().Int0());	// Position is unsigned value
   647 			return KErrNone;
   648 			}
   649 		
   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)
   653 			{
   654 			if(IsDescData(KMsgPtr0))
   655 				Read(KMsgPtr0,pkVal);
   656 			else
   657 				aVal = Message().Int0();	// Seek offset / Size is signed value
   658 			return KErrNone;
   659 			}
   660 		
   661 		aVal = Message().Int0();
   662 		return KErrNone; 
   663 		}
   664 	
   665 	// EFsFileLock and EFsFileUnLock need special treatment
   666 	if(iOperation->Arg(1) == aType) 
   667 		{
   668 		if((iOperation->Function()==EFsFileLock)   ||
   669 		   (iOperation->Function()==EFsFileUnLock)   )
   670 			{
   671 			if(IsDescData(KMsgPtr1))
   672 				Read(KMsgPtr1,pkVal);
   673 			else
   674 				aVal = MAKE_TINT64(0, Message().Int1());	// Length is unsigned value
   675 			return KErrNone; 
   676 			}
   677 		
   678 		aVal = Message().Int1();
   679 		return KErrNone; 
   680 		}
   681 	
   682 	// EFsFileRead, EFsFileWrite, EFsFileSeek and EFsReadFileSection need special treatment
   683 	if(iOperation->Arg(2) == aType) 
   684 		{
   685 		if((iOperation->Function()==EFsFileRead)  ||
   686 		   (iOperation->Function()==EFsFileWrite)   )
   687 			{
   688 			if(IsDescData(KMsgPtr2))
   689 				Read(KMsgPtr2,pkVal);
   690 			else
   691 				{
   692 				if(Message().Int2() == (TInt)I64LOW(KCurrentPosition64))
   693 					aVal = KCurrentPosition64;				// Position is KCurrentPosition64 (-1)
   694 				else
   695 					aVal = MAKE_TINT64(0,Message().Int2());	// Position is unsigned value
   696 				}
   697 			return KErrNone; 
   698 			}
   699 		
   700 		if(iOperation->Function()==EFsFileSeek)
   701 			{
   702 			if(IsDescData(KMsgPtr2))
   703 				Read(KMsgPtr2,pkVal);
   704 			else
   705 				aVal = Message().Int2();	// New position is signed value
   706 			return KErrNone;
   707 			}
   708 		
   709 		if(iOperation->Function()==EFsReadFileSection)
   710 			{
   711 			if(IsDescData(KMsgPtr2))
   712 			Read(KMsgPtr2,pkVal);
   713 			else
   714 			aVal = MAKE_TINT64(0,Message().Int2()); // Position is unsigned value
   715 			return KErrNone;
   716 			}
   717 		
   718 		aVal = Message().Int2();		
   719 		return KErrNone; 
   720 		}
   721 	
   722 	if(iOperation->Arg(3) == aType) 
   723 		{
   724 		aVal = Message().Int3();
   725 		return KErrNone;
   726 		}
   727 	
   728 	return KErrNotSupported;
   729 	}
   730 
   731 void CFsRequest::SetAndOpenScratchValue(const TInt64& aValue)
   732 	{
   733 	if (IsFsObjectOpen())
   734 		{
   735 		((CFsDispatchObject*) I64LOW(iScratchValue))->Close();
   736 		SetFsObjectOpen(EFalse);
   737 		}
   738 	if (I64LOW(aValue) && iOperation && (iOperation->iFlags & EFileShare))
   739 		{
   740 		((CFsDispatchObject*) I64LOW(aValue))->Open();
   741 		SetFsObjectOpen(ETrue);
   742 		}
   743 	iScratchValue = aValue;
   744 	}
   745 
   746 
   747 TInt CFsRequest::Read(TFsPluginRequest::TF32ArgType aType, TDes8& aDes, TInt aOffset)
   748 	{
   749 	TInt slot = GetSlot(aType);
   750 	if(slot >= 0)
   751 		return Read(slot, aDes, aOffset);
   752 	return KErrNotSupported;
   753 	}
   754 
   755 
   756 TInt CFsRequest::Read(TFsPluginRequest::TF32ArgType aType, TDes16& aDes, TInt aOffset)
   757 	{
   758 	TInt slot = GetSlot(aType);
   759 	if(slot >= 0)
   760 		return Read(slot, aDes, aOffset);
   761 	return KErrNotSupported;
   762 	}
   763 
   764 
   765 TInt CFsRequest::Write(TFsPluginRequest::TF32ArgType aType, const TDesC8& aDes, TInt aOffset)
   766 	{
   767 	TInt slot = GetSlot(aType);
   768 	if(slot >= 0)
   769 		return Write(slot, aDes, aOffset);
   770 	return KErrNotSupported;
   771 	}
   772 
   773 
   774 TInt CFsRequest::Write(TFsPluginRequest::TF32ArgType aType, const TDesC16& aDes, TInt aOffset)
   775 	{
   776 	TInt slot = GetSlot(aType);
   777 	if(slot >= 0)
   778 		return Write(slot, aDes, aOffset);
   779 	return KErrNotSupported;
   780 	}
   781 
   782 
   783 TInt CFsRequest::Read(const TInt aMsgPtr,TDes8 &aDes)
   784 	{
   785 	if (Message().Handle() == KLocalMessageHandle)
   786 		{
   787 		TDesC8* pDes = (TDesC8*) ((const RLocalMessage*) &Message())->Arg(aMsgPtr);
   788 		if (aDes.MaxLength() < pDes->Length())
   789 			return KErrTooBig;
   790 		aDes.Copy(*pDes);
   791 		return KErrNone;
   792 		}
   793 
   794 	return Message().Read(aMsgPtr,aDes,0);
   795 	}
   796 
   797 
   798 TInt CFsRequest::Read(const TInt aMsgPtr,TDes8 &aDes,TInt anOffset)
   799 	{
   800 	if (Message().Handle() == KLocalMessageHandle)
   801 		{
   802 		TDesC8* pDes = (TDesC8*) ((const RLocalMessage*) &Message())->Arg(aMsgPtr);
   803 		if (aDes.MaxLength() < pDes->Length() + anOffset)
   804 			return KErrTooBig;
   805 		aDes.SetLength(pDes->Length() + anOffset);
   806 		aDes.MidTPtr(anOffset).Copy(*pDes);
   807 		return KErrNone;
   808 		}
   809 
   810 	return Message().Read(aMsgPtr,aDes,anOffset);
   811 	}
   812 
   813 
   814 TInt CFsRequest::Read(const TInt aMsgPtr,TDes16 &aDes)
   815 	{
   816 	if (Message().Handle() == KLocalMessageHandle)
   817 		{
   818 		TDesC16* pDes = (TDesC16*) ((const RLocalMessage*) &Message())->Arg(aMsgPtr);
   819 		if (aDes.MaxLength() < pDes->Length())
   820 			return KErrTooBig;
   821 		aDes.Copy(*pDes);
   822 		return KErrNone;
   823 		}
   824 
   825 	return Message().Read(aMsgPtr,aDes,0);
   826 	}
   827 
   828 
   829 TInt CFsRequest::Read(const TInt aMsgPtr,TDes16 &aDes,TInt anOffset)
   830 	{
   831 	if (Message().Handle() == KLocalMessageHandle)
   832 		{
   833 		TDesC16* pDes = (TDesC16*) ((const RLocalMessage*) &Message())->Arg(aMsgPtr);
   834 		if (aDes.MaxLength() < pDes->Length() + anOffset)
   835 			return KErrTooBig;
   836 		aDes.SetLength(pDes->Length() + anOffset);
   837 		aDes.MidTPtr(anOffset).Copy(*pDes);
   838 		return KErrNone;
   839 		}
   840 
   841 	return Message().Read(aMsgPtr,aDes,anOffset);
   842 	}
   843 
   844 
   845 TInt CFsRequest::Write(const TInt aMsgNum,const TDesC8 &aDes)
   846 	{
   847 	if (Message().Handle() == KLocalMessageHandle)
   848 		{
   849 		TDes8* pDes = (TDes8*) ((const RLocalMessage*) &Message())->Arg(aMsgNum);
   850 		if (pDes->MaxLength() < aDes.Length())
   851 			return KErrTooBig;
   852 		pDes->Copy(aDes);
   853 		return KErrNone;
   854 		}
   855 
   856 	return Message().Write(aMsgNum,aDes,0);
   857 	}
   858 
   859 
   860 TInt CFsRequest::Write(const TInt aMsgNum,const TDesC8 &aDes,TInt anOffset)
   861 	{
   862 	if (Message().Handle() == KLocalMessageHandle)
   863 		{
   864 		TDes8* pDes = (TDes8*) ((const RLocalMessage*) &Message())->Arg(aMsgNum);
   865 		if (pDes->MaxLength() < aDes.Length() + anOffset)
   866 			return KErrTooBig;
   867 		pDes->SetLength(aDes.Length() + anOffset);
   868 		pDes->MidTPtr(anOffset).Copy(aDes);
   869 		return KErrNone;
   870 		}
   871 
   872 	return Message().Write(aMsgNum,aDes,anOffset);
   873 	}
   874 
   875 
   876 TInt CFsRequest::Write(const TInt aMsgNum,const TDesC16 &aDes)
   877 	{
   878 	if (Message().Handle() == KLocalMessageHandle)
   879 		{
   880 		TDes16* pDes = (TDes16*) ((const RLocalMessage*) &Message())->Arg(aMsgNum);
   881 		if (pDes->MaxLength() < aDes.Length())
   882 			return KErrTooBig;
   883 		pDes->Copy(aDes);
   884 		return KErrNone;
   885 		}
   886 
   887 	return Message().Write(aMsgNum,aDes,0);
   888 	}
   889 
   890 
   891 TInt CFsRequest::Write(const TInt aMsgNum,const TDesC16 &aDes,TInt anOffset)
   892 	{
   893 	if (Message().Handle() == KLocalMessageHandle)
   894 		{
   895 		TDes16* pDes = (TDes16*) ((const RLocalMessage*) &Message())->Arg(aMsgNum);
   896 		if (pDes->MaxLength() < aDes.Length() + anOffset)
   897 			return KErrTooBig;
   898 		pDes->SetLength(aDes.Length() + anOffset);
   899 		pDes->MidTPtr(anOffset).Copy(aDes);
   900 		return KErrNone;
   901 		}
   902 
   903 	return Message().Write(aMsgNum,aDes,anOffset);
   904 	}
   905 
   906 
   907 void CFsRequest::ReadL(const TInt aMsgPtr,TDes8 &aDes)
   908 	{ User::LeaveIfError(Read(aMsgPtr,aDes)); }
   909 
   910 void CFsRequest::ReadL(const TInt aMsgPtr,TDes8 &aDes,TInt anOffset)
   911 	{ User::LeaveIfError(Read(aMsgPtr,aDes,anOffset)); }
   912 
   913 void CFsRequest::ReadL(const TInt aMsgPtr,TDes16 &aDes)
   914 	{ User::LeaveIfError(Read(aMsgPtr,aDes)); }
   915 
   916 void CFsRequest::ReadL(const TInt aMsgPtr,TDes16 &aDes,TInt anOffset)
   917 	{ User::LeaveIfError(Read(aMsgPtr,aDes,anOffset)); }
   918 
   919 void CFsRequest::WriteL(const TInt aMsgNum,const TDesC8 &aDes)
   920 	{ User::LeaveIfError(Write(aMsgNum,aDes)); }
   921 
   922 void CFsRequest::WriteL(const TInt aMsgNum,const TDesC8 &aDes,TInt anOffset)
   923 	{ User::LeaveIfError(Write(aMsgNum,aDes,anOffset)); }
   924 
   925 void CFsRequest::WriteL(const TInt aMsgNum,const TDesC16 &aDes)
   926 	{ User::LeaveIfError(Write(aMsgNum,aDes)); }
   927 
   928 void CFsRequest::WriteL(const TInt aMsgNum,const TDesC16 &aDes,TInt anOffset)
   929 	{ User::LeaveIfError(Write(aMsgNum,aDes,anOffset)); }
   930 
   931 
   932 /**
   933     @param  aMsgNum message argument index 
   934     @return client side descriptor length 
   935 */
   936 TInt CFsRequest::GetDesLength(const TInt aMsgNum)
   937 	{
   938 	if (Message().Handle() == KLocalMessageHandle)
   939 		{
   940 		TDes8* pDes = (TDes8*) ((const RLocalMessage*) &Message())->Arg(aMsgNum);
   941 		return pDes->Length();
   942 		}
   943 	else
   944 		{
   945 		return Message().GetDesLength(aMsgNum);
   946 		}
   947 	}
   948 
   949 const RMessage2& CFsRequest::Message()
   950 //
   951 //
   952 //
   953 	{
   954 	Fault(EBaseRequestMessage);
   955 	return(dummyM);
   956 	}
   957 
   958 
   959 
   960 void CFsMessageRequest::Set(const RMessage2& aMessage,CSessionFs* aSession)
   961 //
   962 // For reuseable request
   963 //
   964 	{
   965 	iMessage=aMessage;
   966 	iDrive=NULL;
   967 	iSubstedDrive=NULL;
   968 	CFsRequest::Set(aSession);
   969 	SetFreeChanged(EFalse);
   970 	EnablePostIntercept(ETrue);
   971 	}
   972 
   973 	
   974 void CFsMessageRequest::Set(const RMessage2& aMessage,const TOperation& aOperation,CSessionFs* aSession)
   975 //
   976 //
   977 //
   978 	{
   979 	iCurrentPlugin=NULL;
   980 	iMessage=aMessage;
   981 	iDrive=NULL;
   982 	iSubstedDrive=NULL;
   983 	CFsRequest::Set(aOperation,aSession);
   984 	SetFreeChanged(EFalse);
   985 	EnablePostIntercept(ETrue);
   986 	}
   987 
   988 void CFsMessageRequest::Set(const TOperation& aOperation)
   989 	{
   990 	iOperation=const_cast<TOperation*>(&aOperation);
   991 	}
   992 
   993 void CFsMessageRequest::Process()
   994 //
   995 // Process the request - (passing to a plugin or a drive thread)
   996 //
   997 	{
   998 	__THRD_PRINT3(_L("CFsMessageRequest::Process() req %08x state %d plugin 0x%x"), this, iReqState, iCurrentPlugin);
   999 	
  1000 	// initialise request - if not initialised already
  1001 	if (iReqState == EReqStateInitialise)
  1002 		{
  1003 		TInt r = DoInitialise();
  1004 		if (r == EReqActionComplete)
  1005 			{
  1006 			return;
  1007 			}
  1008 		else if (r == EReqActionBusy)	// request postponed ?
  1009 			{
  1010 			SetState(EReqStateInitialise);
  1011 			Dispatch(EFalse);
  1012 			return;
  1013 			}
  1014 		else if (r == KErrNone && iCurrentPlugin)		// dispatch to plugin thread ?
  1015 			{
  1016 			Dispatch(EFalse);
  1017 			return;
  1018 			}
  1019 		}
  1020 
  1021 	if(iCurrentPlugin)
  1022 		{
  1023 		if (IsPostOperation())
  1024 			{
  1025 			ProcessPostOperation();
  1026 			return;
  1027 			}
  1028 			
  1029 		if(!IsPluginSpecific())
  1030 			{
  1031 			ProcessPreOperation();
  1032 			return;
  1033 			}
  1034 		}
  1035 
  1036 	
  1037 	// Is there a PostInitialise function ?
  1038 	if (iReqState == EReqStatePostInitialise)
  1039 		{
  1040 		TInt r = PostInitialise();
  1041 		if (r == EReqActionComplete)
  1042 			{
  1043 			return;
  1044 			}
  1045 		else if (r == EReqActionBusy)	// request postponed ?
  1046 			{
  1047 			SetState(EReqStatePostInitialise);
  1048 			Dispatch(EFalse);
  1049 			return;
  1050 			}
  1051 		}
  1052 
  1053 	ProcessDriveOperation();
  1054 	}
  1055 	
  1056 void CFsMessageRequest::ProcessPostOperation()
  1057 //
  1058 // Process the message in post operation mode (handled by the current plugin)
  1059 //
  1060 	{
  1061 	TInt err = KErrNone;
  1062 	if(!iCurrentPlugin->IsPluginThread(*this))
  1063 		{
  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)
  1068 			{
  1069 			Panic(KFsClient,leaveValue);
  1070 			if(iOperation->IsOpenSubSess())		
  1071 				RequestAllocator::OpenSubFailed(Session());
  1072 			Free();
  1073 			return;
  1074 			}
  1075 
  1076 		if(!IsExpectedResult(err))
  1077 			{
  1078 			Complete(err);
  1079 			return;
  1080 			}
  1081 		}
  1082 	
  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)
  1087 		{
  1088 		Complete(GetError());
  1089 		return;
  1090 		}
  1091 
  1092 	Dispatch();
  1093 	return;
  1094 	}
  1095 	
  1096 
  1097 void CFsMessageRequest::ProcessPreOperation()
  1098 //
  1099 // Process the message in pre operation mode (handled by the current plugin)
  1100 //
  1101 	{
  1102 	TInt err = KErrNone;
  1103 	if(!iCurrentPlugin->IsPluginThread(*this))
  1104 		{
  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);
  1109 
  1110 		if((iOperation->Function() == EFsDismountPlugin) && (err !=  KErrPermissionDenied))
  1111 			{
  1112 			TRAP(leaveValue, err = iOperation->DoRequestL(this));
  1113 			}
  1114 
  1115 		if(leaveValue != KErrNone)
  1116 			{
  1117 			Panic(KFsClient,leaveValue);
  1118 			if(iOperation->IsOpenSubSess())		//this should be close subsession
  1119 				RequestAllocator::OpenSubFailed(Session());	//need a close subsession fail
  1120 			Free();
  1121 			return;
  1122 			}
  1123 		}
  1124 
  1125 	if(err == KErrNone)
  1126 		{
  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);
  1133 		Dispatch();
  1134 		return;
  1135 		}
  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)
  1139 		{
  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)
  1144 			{
  1145 			SetPostOperation(ETrue);
  1146 			err = KErrNone;
  1147 			Dispatch();
  1148 			return;
  1149 			}
  1150 		else
  1151 			{
  1152 			err = KErrNone;	
  1153 			}
  1154 		}
  1155 		
  1156 	Complete(err);
  1157 	return;
  1158 	}
  1159 
  1160 
  1161 void CFsMessageRequest::ProcessDriveOperation()
  1162 //
  1163 // Process the message in drive (or main thread) context
  1164 //
  1165 	{
  1166 
  1167 	// A new request is to be processed - kick off the inactivity/finalisation timer...
  1168 	FsThreadManager::StartFinalisationTimer(iDriveNumber);
  1169 
  1170 	TInt err = KErrNone;
  1171 	
  1172 	TRAPD(leaveValue, err = iOperation->DoRequestL(this));
  1173 
  1174 	// Cancel hung state if a request from the drive thread has finished
  1175 	FsThreadManager::SetDriveHung(DriveNumber(), EFalse);
  1176 
  1177 	if(leaveValue != KErrNone)
  1178 		{
  1179 		Panic(KFsClient,leaveValue);
  1180 		if(iOperation->IsOpenSubSess()) 
  1181 			RequestAllocator::OpenSubFailed(Session());
  1182 		Free();
  1183 		return;
  1184 		}
  1185 		
  1186 	// request postponed ? (e.g. if a page used by file cache is busy,
  1187 	// or because of fair scheduling).
  1188 	if (err == EReqActionBusy)
  1189 		{
  1190 		Dispatch();
  1191 		return;
  1192 		}
  1193 
  1194 	iLastError = err;
  1195 
  1196 	if(!IsExpectedResult(err) || IsPluginSpecific())
  1197 		{
  1198 		// no need to call DoNotify here since that requires err==KErrNone
  1199 		Complete(err);
  1200 		return;
  1201 		}
  1202 
  1203 	SetError(err);
  1204 
  1205 
  1206 	// Start issuing the post-operation requests starting from the bottom of the chain
  1207 	iCurrentPlugin = NULL;
  1208 	if (PostInterceptEnabled())
  1209 		{
  1210 		FsPluginManager::PrevPlugin(iCurrentPlugin, this,(TBool)ETrue);
  1211 		if(iCurrentPlugin && !iCurrentPlugin->IsPluginThread(*this))
  1212 			{
  1213 			SetPostOperation(ETrue);
  1214 			if (DispatchToPlugin())
  1215 				return;
  1216 			}
  1217 		}		
  1218 
  1219 	Complete(GetError());
  1220 	return;
  1221 	}
  1222 
  1223 void CFsMessageRequest::Complete(TInt aError)
  1224 //
  1225 //
  1226 //
  1227 	{
  1228 	__THRD_PRINT2(_L("----- CFsMessageRequest::Complete() req %08x with %d"), this, aError);
  1229 
  1230 	if (aError==KErrNoMemory)
  1231 		{
  1232 		if (iDrive)	// Not all message requests are associated with a drive!
  1233 			{
  1234 			TDriveInfo di;
  1235 			iDrive->DriveInfo(di);
  1236 			if (di.iType == EMediaRam)
  1237 				aError = KErrNoMemory;
  1238 			}
  1239 		}
  1240 	if(aError!=KErrNone)
  1241 		{
  1242 		if(iOperation->IsOpenSubSess())
  1243 			RequestAllocator::OpenSubFailed(Session());
  1244 		}
  1245 
  1246 	iLastError = aError;
  1247 
  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.
  1251 	//
  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, 
  1257 	TInt completeErr;
  1258 
  1259 	for (completeErr = EReqActionComplete; CurrentOperationPtr() != NULL && completeErr == EReqActionComplete; )
  1260 		{
  1261 		// Get the completion routine from the current TMsgOperation and then pop it
  1262 		TFsRequestFunc doComplete = CurrentOperation().iComplete;
  1263 		PopOperation();
  1264 		
  1265 		// Check that a completion routine is supplied if this isn't the last TMsgOperation
  1266 		__ASSERT_ALWAYS(iCurrentOperation == NULL || doComplete != NULL, Fault(EBadOperationIndex));
  1267 
  1268 		// Call the completion routine
  1269 		if (doComplete)
  1270 			completeErr = doComplete(this);
  1271 
  1272 		// Check return code is valid
  1273 		__ASSERT_DEBUG(completeErr == EReqActionContinue || completeErr == EReqActionBusy || completeErr == EReqActionComplete || completeErr == EReqActionOwnedByPlugin, Fault(EBadOperationCompletionCode));
  1274 		}
  1275 
  1276 	// a set of flags to determine what actions to take for each return code
  1277 	enum 
  1278 		{
  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
  1284 		};
  1285 	const TUint actions[8] = 
  1286 		{
  1287 		// 0 - EReqActionContinue
  1288 		EDispatch,											
  1289 		// 1 - unused
  1290 		0,
  1291 		// 2 - unused
  1292 		0,
  1293 		// 3 - unused
  1294 		0,
  1295 		// 4 - EReqActionCompleteAndDispatch
  1296 		EDispatch | EComplete | EResetPostInitialised | EDispatchToFront,
  1297 		// 5 - EReqActionOwnedByPlugin
  1298 		0,													
  1299 		// 6 - EReqActionBusy
  1300 		EDispatch | EResetPostInitialised,					
  1301 		// 7 - EReqActionComplete
  1302 		EComplete | EFree,
  1303 		};
  1304 
  1305 	TUint actionFlags = actions[((TUint32) completeErr) & 0x00000007];
  1306 
  1307 	// To dispatch to drive thread and intercept before DoRequestL() 
  1308 	// we must re-call iPostInitialise(), so reset iPostInitialised flag
  1309 	if (actionFlags & EResetPostInitialised)
  1310 		{
  1311 		// can only postpone the request if there's a PostInitialise() function
  1312 		__ASSERT_DEBUG(iOperation->iPostInitialise , Fault(EBadOperationCompletionCode));
  1313 		SetState(EReqStatePostInitialise);
  1314 		}
  1315 
  1316 
  1317 
  1318 	TInt dispatchError = KErrNone;
  1319 	TBool completeMessage = (iLastError != KErrNone) || (iIsCompleted && (actionFlags & EComplete));
  1320 
  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;
  1324 	if (drive) 
  1325 		drive->Lock();
  1326 
  1327 	// don't go back up plugin chain once message has been completed
  1328 	if (completeMessage)
  1329 		EnablePostIntercept(EFalse);
  1330 
  1331 	if (actionFlags & EDispatch)
  1332 		{
  1333 		__ASSERT_DEBUG(((actionFlags & EFree) == 0), Fault(EInvalidCompletionFlags));
  1334 		__ASSERT_DEBUG (iCurrentPlugin == NULL, Fault(EInvalidMsgState));
  1335 		dispatchError = DispatchToDrive(EFalse, actionFlags & EDispatchToFront);
  1336 		}
  1337 
  1338 	
  1339 	if ((actionFlags & EComplete) && IsExpectedResult(iLastError) && !IsPluginSpecific() && !IsNotifierSpecific())
  1340 		DoNotify(KErrNone);
  1341 
  1342 
  1343 	if (completeMessage)
  1344 		{
  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);
  1351 		}
  1352 
  1353 	if(iOperation->Function() == EFsFileSubClose)
  1354 		{
  1355 		HBufC* pFileName = (HBufC*) I64HIGH(ScratchValue64());
  1356 		if(pFileName)
  1357 			{
  1358 			delete pFileName;
  1359 			SetScratchValue(NULL);
  1360 			}
  1361 		}
  1362 
  1363 	if (drive) 
  1364 		drive->UnLock();
  1365 
  1366 	if (actionFlags & EFree)
  1367 		Free();
  1368 
  1369 	// if the dispatch failed, then continue with popping MessageOps from the stack.
  1370 	if (dispatchError != KErrNone)
  1371 		Complete(dispatchError);
  1372 	}
  1373 
  1374 void CFsMessageRequest::DoNotify(TInt aError)
  1375 //
  1376 //
  1377 //
  1378 	{
  1379 	__PRINT1(_L("----- CFsMessageRequest::DoNotify() with %d"),aError);
  1380 
  1381 	TInt driveNumber = DriveNumber();
  1382 
  1383 	if(aError==KErrNone)
  1384 		{
  1385 		if(!(FsNotify::IsChangeQueEmpty(driveNumber)))
  1386 			FsNotify::HandleChange(this,driveNumber);	
  1387 		if ((driveNumber != KDriveInvalid) && !(FsNotify::IsDiskSpaceQueEmpty(driveNumber)))
  1388 			FsNotify::HandleDiskSpace(this, DriveNumber());
  1389 	
  1390 #ifdef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
  1391 		if 	(iOperation->iFunction == EFsFileWrite)
  1392 			{
  1393 			CFileShare* share = (CFileShare*) this->ScratchValue();
  1394 			CFileCB* file = &share->File();
  1395 			CFileCache* fileCache = file->FileCache();
  1396 			
  1397 			// Manage notifications for write with no cache or a write-through
  1398 			if (!fileCache || !fileCache->IsDirty())
  1399 				{
  1400 				FsNotificationManager::HandleChange((CFsClientMessageRequest&)*this);
  1401 				}
  1402 			}
  1403 		else if((iOperation->iFunction == EFsFileWriteDirty) && FsNotificationManager::IsInitialised())
  1404 			{
  1405 			CFileShare* share;
  1406 			CFileCB* file;
  1407 			GetFileFromScratch(this, share, file);
  1408 
  1409 			TFileName path;
  1410 			path.Append(file->DriveNumber() + 'A');
  1411 			path.Append(':');
  1412 			path.Append(file->FileName().Des());
  1413 			
  1414 			// Manage notifications for write with caching enabled
  1415 			FsNotificationManager::HandleChange((CFsClientMessageRequest*)this, path, TFsNotification::EFileChange);
  1416 			}
  1417 		else if(IsNotifierSupported())
  1418 			{
  1419 			FsNotificationManager::HandleChange((CFsClientMessageRequest&)*this);
  1420 			}
  1421 #endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
  1422 		}
  1423 	}
  1424 
  1425 
  1426 void CFsMessageRequest::Free()
  1427 //
  1428 //
  1429 //
  1430 	{
  1431 	__THRD_PRINT1(_L("CFsMessageRequest::Free() isAllocated=%d"), IsAllocated());
  1432 
  1433 	SetScratchValue(0);	// this should close the CFsObject
  1434 
  1435 	if(!IsAllocated())
  1436 		delete(this);
  1437 	else iOperation = NULL;
  1438 
  1439 	}
  1440 
  1441 TInt CFsMessageRequest::DoInitialise()
  1442 //
  1443 // returns KErrNone if Initialise succeeded normally
  1444 // or      EReqActionComplete if request completed already
  1445 // or      EReqActionBusy if request needs dispatching & initialising again
  1446 //
  1447 	{
  1448 	TInt r = KErrNone;
  1449 
  1450 	SetState(iOperation->iPostInitialise ? EReqStatePostInitialise : EReqStateDoRequest);
  1451 	r=Initialise();
  1452 	if(r==KErrBadHandle)
  1453 		{
  1454 		// bad subsession handle so panic client
  1455 		_LIT(KPanic,"Panic");
  1456 		Panic(KPanic,r);
  1457 		if(iOperation->IsOpenSubSess())			//this should be close subsession
  1458 			RequestAllocator::OpenSubFailed(Session());	//need a close subsession fail
  1459 		Free();
  1460 		r = EReqActionComplete;
  1461 		}
  1462 	else if (r == EReqActionComplete)	// completed synchronously in Initialise() function ?
  1463 		{
  1464 		Complete(KErrNone);
  1465 		}
  1466 	else if (r == EReqActionBusy || r == EReqActionPending)	// request postponed or owned by file share ?
  1467 		{
  1468 		}
  1469 	else if (r != KErrNone)			// error 
  1470 		{
  1471 		Complete(r);
  1472 		r = EReqActionComplete;
  1473 		}
  1474 
  1475 	return r;
  1476 	}
  1477 
  1478 TInt CFsMessageRequest::PostInitialise()
  1479 //
  1480 // returns KErrNone if PostInitialise() succeeded normally
  1481 // or      EReqActionComplete if request completed already
  1482 // or      EReqActionBusy if request needs dispatching & initialising again
  1483 //
  1484 	{
  1485 	TInt r = KErrNone;
  1486 
  1487 	SetState(EReqStateDoRequest);
  1488 	if (iOperation->iPostInitialise)
  1489 		r = iOperation->iPostInitialise(this);
  1490 	if (r == EReqActionComplete)		// completed early ?
  1491 		{
  1492 
  1493 		// Start issuing the post-operation requests starting from the bottom of the chain
  1494 		iCurrentPlugin = NULL;
  1495 		if (PostInterceptEnabled())
  1496 			{
  1497 			FsPluginManager::PrevPlugin(iCurrentPlugin, this,(TBool)ETrue);
  1498 			if(iCurrentPlugin && !iCurrentPlugin->IsPluginThread(*this))
  1499 				{
  1500 				SetPostOperation(ETrue);
  1501 				Dispatch();
  1502 				return r;	// EReqActionComplete
  1503 				}
  1504 			}		
  1505 
  1506 		Complete(KErrNone);
  1507 		}
  1508 	else if (r == EReqActionBusy)	// request postponed ?
  1509 		{
  1510 		}
  1511 	else if (r != KErrNone)			// error 
  1512 		{
  1513 		Complete(r);
  1514 		r = EReqActionComplete;
  1515 		}
  1516 
  1517 	return r;
  1518 	}
  1519 
  1520 
  1521 // CFsMessageRequest::Dispatch()
  1522 //
  1523 // If aInitialise is EFalse, just disptach request to appropriate thread - 
  1524 // don't call DoInitialise() or PostInitialise()
  1525 //
  1526 void CFsMessageRequest::Dispatch(TBool aInitialise, TBool aLowPriority, TBool aDispatchToFront)
  1527 	{
  1528 	__THRD_PRINT1(_L("CFsMessageRequest::Dispatch() req %08x"), this);
  1529 
  1530 	TInt r = KErrNone;
  1531 
  1532 	if (iReqState == EReqStateInitialise && aInitialise)
  1533 		{
  1534 		r = DoInitialise();
  1535 		if (r == EReqActionComplete)
  1536 			{
  1537 			return;
  1538 			}
  1539 		else if (r == EReqActionBusy)		// request postponed ?
  1540 			{
  1541 			SetState(EReqStateInitialise);	// reinitialize when request is next processed
  1542 			}
  1543 		else if (r == EReqActionPending)	// owned by file share ?
  1544 			{
  1545 			SetState(EReqStateInitialise);	// reinitialize when request is next processed
  1546 			return;
  1547 			}
  1548 		if(!IsPluginSpecific() && (iOwnerPlugin == NULL))
  1549 			{
  1550 			iCurrentPlugin = NULL;
  1551 			iClientThreadId = 0;
  1552 			FsPluginManager::NextPlugin(iCurrentPlugin, this, (TBool)ETrue);
  1553 
  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);
  1558 
  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)
  1562 				{
  1563 				RThread thread;
  1564 				Message().Client(thread, EOwnerThread);
  1565 				iClientThreadId = thread.Id();
  1566 				thread.Close();
  1567 				}
  1568 			} 
  1569 		} // initialise
  1570 		
  1571 
  1572 		// dispatch to plugin thread if initialised (otherwise dispatch to drive thread)
  1573 	if (iReqState > EReqStateInitialise && DispatchToPlugin())
  1574 		{
  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
  1578 		return;
  1579 		}
  1580 
  1581 
  1582 	// Is there a PostInitialise function ?
  1583 	if (iReqState ==  EReqStatePostInitialise && aInitialise && r == KErrNone)
  1584 		{
  1585 		TInt r = PostInitialise();
  1586 		if (r == EReqActionComplete)
  1587 			return;
  1588 		else if (r == EReqActionBusy)				// request postponed ?
  1589 			SetState(EReqStatePostInitialise);		// reinitialize when request is next processed
  1590 		}
  1591 
  1592 
  1593 	if(!IsSeparateThread() || FsThreadManager::IsDriveSync(DriveNumber(),EFalse))
  1594 		{
  1595 		__PLUGIN_PRINT1(_L("PLUGIN: CFsMessageRequest %x dispatched to plugin (sync)"), this);
  1596 		FsPluginManager::DispatchSync(this);
  1597 		return;
  1598 		}
  1599 
  1600 	r = DispatchToDrive(aLowPriority, aDispatchToFront);
  1601 	if (r != KErrNone)
  1602 		Complete(r);
  1603 	}
  1604 
  1605 inline TInt CFsMessageRequest::DispatchToDrive(TBool aLowPriority, TBool aDispatchToFront)
  1606 	{
  1607 	TInt drivenumber = DriveNumber();
  1608 	
  1609 	if (drivenumber < EDriveA || drivenumber > EDriveZ)
  1610 		return KErrNotSupported;
  1611 	
  1612 	FsThreadManager::LockDrive(drivenumber);
  1613 
  1614 	CDriveThread* dT=NULL;
  1615 	TInt r = FsThreadManager::GetDriveThread(drivenumber,&dT);
  1616 
  1617 	if(r == KErrNone)
  1618 		{
  1619 		CRequestThread* pT = (CRequestThread*)dT;
  1620 
  1621 		if (FsThreadManager::IsDriveHung(drivenumber))
  1622 			r = KErrNotReady;
  1623 		else if (aDispatchToFront)
  1624 			pT->DeliverFront(this);
  1625 		else
  1626 			pT->DeliverBack(this, aLowPriority);
  1627 		}
  1628 	else if (r == KErrAccessDenied)
  1629 		{
  1630 		Process();
  1631 		}
  1632 
  1633 	FsThreadManager::UnlockDrive(drivenumber);
  1634 
  1635 	return r;
  1636 	}
  1637 
  1638 void CFsMessageRequest::Dispatch()
  1639 	{
  1640 	Dispatch(ETrue);
  1641 	}
  1642 
  1643 TBool CFsMessageRequest::DispatchToPlugin()
  1644 //
  1645 // Common route: Receive -> Process -> Dispatch -> DispatchToPlugin
  1646 //
  1647 	{
  1648 	TInt drivenumber = DriveNumber();
  1649 	if(iCurrentPlugin)
  1650 		{		
  1651 		FOREVER
  1652 			{
  1653 			// if we've reached a plugin which is waiting for Complete(), stop going up the plugin chain
  1654 			if(drivenumber >= 0 && IsPostOperation() && CurrentPluginWaiting())
  1655 				{
  1656 				// No more plug-ins need to process this request
  1657 				iCurrentPlugin = NULL;
  1658 				}
  1659 
  1660 			while(iCurrentPlugin && iCurrentPlugin->IsPluginThread(*this))
  1661 				{
  1662 				// Skip the current plugin if the request originated from the plugin
  1663 				if(IsPostOperation())
  1664 					{
  1665 					FsPluginManager::PrevPlugin(iCurrentPlugin, this,(TBool)ETrue);
  1666 					}
  1667 				else
  1668 					{
  1669 					FsPluginManager::NextPlugin(iCurrentPlugin, this,(TBool)ETrue);
  1670 					}
  1671 				}
  1672 				
  1673 			if(iCurrentPlugin)
  1674 				{
  1675 				TFsPluginRequest request(this);
  1676 				 __THRD_PRINT1(_L("CFsMessageRequest::DispatchToPlugin() req %08x"), this);
  1677 
  1678 				TInt err = iCurrentPlugin->Deliver(request);
  1679 				if(err == KErrNone)
  1680 					{
  1681 
  1682 					// The request has been delivered to the plugin thread
  1683 					//  - leave the main thread now
  1684 					return(ETrue);
  1685 					}
  1686 				else if(err < KErrNone)
  1687 					{
  1688 					// An error has occurred
  1689 					//  - complete the message
  1690 					Complete(err);
  1691 					return(ETrue);
  1692 					}
  1693 				else if(err == KPluginMessageForward)
  1694 					{
  1695 					// The plugin has processed synchronously (case 1)
  1696 					//  - Pass the message on to the next plugin
  1697 					if(FsFunction() != EFsPluginOpen)
  1698 					    {
  1699 	                    FsPluginManager::NextPlugin(iCurrentPlugin, this,(TBool)ETrue);
  1700 	                    continue;
  1701 					    }
  1702 					else // FsFunction == EFsPluginOpen
  1703 					    {
  1704 					    /* 
  1705 					     * PluginOpen requests should not be passed down the plugin stack.
  1706 					     * 
  1707 
  1708 					     */
  1709 					    iCurrentPlugin = NULL;
  1710 					    continue;
  1711 					    }
  1712 					}
  1713 				else if(err == KPluginMessageComplete)
  1714 					{
  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);
  1719 					continue;
  1720 					}
  1721 				_LIT(KPanic,"Panic: F32-BAD-PLUGIN-ERROR");
  1722 				Panic(KPanic, err);
  1723 				}
  1724 			else if (IsPostOperation())
  1725 				{
  1726 				// No more plugins are interested in this request
  1727 				//	 - If in post operation, complete the request
  1728 				Complete(GetError());
  1729 				return(ETrue);
  1730 				}
  1731 			else
  1732 				{
  1733 				// No plugin is registered for pre-operation interception this message
  1734 				//	- pass the request onto the drive thread.
  1735 				return EFalse;
  1736 				}
  1737 			}			
  1738 		}
  1739 
  1740 	if(iOperation->Function() == EFsDismountPlugin)
  1741 		{
  1742 		// Don't pass plugin dismounts to the drive thread
  1743 		Process();
  1744 		return(ETrue);
  1745 		}
  1746 		
  1747 	return EFalse;
  1748 	}
  1749 
  1750 TDrive* CFsMessageRequest::Drive()
  1751 //
  1752 //
  1753 //
  1754 	{
  1755 	return(iDrive);
  1756 	}
  1757 
  1758 TDrive* CFsMessageRequest::SubstedDrive()
  1759 //
  1760 //
  1761 //
  1762 	{
  1763 	return(iSubstedDrive);
  1764 	}
  1765 
  1766 void CFsMessageRequest::SetDrive(TDrive* aDrive)
  1767 //
  1768 //
  1769 //
  1770 	{
  1771 	iDrive=aDrive;
  1772 	if(aDrive)
  1773 		{
  1774 		iDriveNumber=aDrive->DriveNumber();
  1775 		}
  1776 	}
  1777 
  1778 void CFsMessageRequest::SetSubstedDrive(TDrive* aDrive)
  1779 //
  1780 //
  1781 //
  1782 	{
  1783 	iSubstedDrive=aDrive;
  1784 	}
  1785 
  1786 const RMessage2& CFsMessageRequest::Message()
  1787 //
  1788 //
  1789 //
  1790 	{
  1791 	return(iMessage);
  1792 	}
  1793 
  1794 
  1795 
  1796 void CFsMessageRequest::ReStart()
  1797 	{
  1798 	__ASSERT_ALWAYS(CurrentOperationPtr() != NULL, Fault(EBadOperationIndex));
  1799 
  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));
  1810 	}
  1811 
  1812 
  1813 void CFsMessageRequest::SetOperationFunc(TInt aFunction)
  1814 	{
  1815 	const TOperation& oP = OperationArray[aFunction];
  1816 	Set(oP);
  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));
  1819 	}
  1820 
  1821 TInt CFsMessageRequest::PushOperation(TFsRequestFunc aCallback, TInt aNextState, TInt aFunction)
  1822 	{
  1823 	TMsgOperation* nextOperation;
  1824 	TInt r = RequestAllocator::GetOperation(nextOperation);
  1825 	if (r != KErrNone)
  1826 		return r;
  1827 
  1828 	
  1829 	// Store the caller's state etc in the CURRENT TMsgOperation (if there is one)
  1830 	if (iCurrentOperation != NULL)
  1831 		{
  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;
  1838 		}
  1839 
  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);
  1845 
  1846 
  1847 	iCurrentOperation = nextOperation;
  1848 	
  1849 	// reset post operation state: as a plugin may push more than one TMsgOperation
  1850 	SetPostOperation(EFalse);
  1851 
  1852 	return KErrNone;
  1853 	}
  1854 
  1855 /**
  1856 PushOperation()
  1857 
  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). 
  1860 
  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).
  1864 
  1865 @param aPos			The position to read / write. Stored in the NEW TMsgOperation.
  1866 
  1867 @param aLength		The length to read / write. Stored in the NEW TMsgOperation.
  1868 
  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
  1871 
  1872 @param aOffset		The offset onto the buffer to read from / write to. Stored in the NEW TMsgOperation.
  1873 
  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
  1876 
  1877 @param aNextState	State information private to the caller. Defaults to zero. Stored in the OLD TMsgOperation.
  1878 
  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.
  1882 					
  1883 */
  1884 TInt CFsMessageRequest::PushOperation(TInt64 aPos, TInt aLength, TUint8* aData, TInt aOffset, TFsRequestFunc aCallback, TInt aNextState, TInt aFunction)
  1885 	{
  1886 	TInt r = PushOperation(aCallback, aNextState, aFunction);
  1887 	if (r == KErrNone)
  1888 		CurrentOperation().Set(aPos, aLength, aData, aOffset, 0);
  1889 	return r;
  1890 	}
  1891 
  1892 
  1893 /**
  1894 PushOperation()
  1895 
  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). 
  1898 
  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).
  1902 
  1903 @param aPos			The position to read / write. Stored in the NEW TMsgOperation.
  1904 
  1905 @param aLength		The length to read / write. Stored in the NEW TMsgOperation.
  1906 
  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.
  1909 
  1910 @param aOffset		The offset onto the buffer to read from / write to. Stored in the NEW TMsgOperation.
  1911 
  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
  1914 
  1915 @param aNextState	State information private to the caller. Defaults to zero. Stored in the OLD TMsgOperation.
  1916 
  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.
  1920 					
  1921 */
  1922 TInt CFsMessageRequest::PushOperation(TInt64 aPos, TInt aLength, TDesC8* aData, TInt aOffset, TFsRequestFunc aCallback, TInt aNextState, TInt aFunction)
  1923 	{
  1924 	TInt r = PushOperation(aCallback, aNextState, aFunction);
  1925 	if (r == KErrNone)
  1926 		CurrentOperation().Set(aPos, aLength, aData, aOffset, 0);
  1927 	return r;
  1928 	}
  1929 
  1930 void CFsMessageRequest::PopOperation()
  1931 	{
  1932 	__ASSERT_ALWAYS(iCurrentOperation != NULL, Fault(EInvalidOperationIndex));
  1933 	
  1934 	TMsgOperation* currentOperation = iCurrentOperation;
  1935 	
  1936 	if (iCurrentOperation->iPrev == NULL)
  1937 		{
  1938 		iCurrentOperation = NULL;
  1939 		}
  1940 	else
  1941 		{
  1942 		TMsgOperation* prevOperation = iCurrentOperation->iPrev;
  1943 		prevOperation->iNext = NULL;
  1944 		iCurrentOperation = prevOperation;
  1945 
  1946 		iCurrentPlugin = iCurrentOperation->iCurrentPlugin;
  1947 		
  1948 		if (iCurrentOperation->iFunction != iOperation->Function())
  1949 			SetOperationFunc(iCurrentOperation->iFunction);
  1950 		}
  1951 
  1952 	RequestAllocator::FreeOperation(currentOperation);
  1953 	}
  1954 
  1955 TMsgOperation& CFsMessageRequest::CurrentOperation()
  1956 	{
  1957 	__ASSERT_ALWAYS(iCurrentOperation != NULL, Fault(EInvalidOperationIndex));
  1958 	return *iCurrentOperation;
  1959 	}
  1960 
  1961 
  1962 CFsClientMessageRequest::CFsClientMessageRequest()
  1963 : iPoolSrc (0),
  1964   iPoolDest(0)
  1965 	{
  1966 	}
  1967 
  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()
  1972 	{
  1973 	if (iOwnerPlugin == iCurrentPlugin)
  1974 		return ETrue;
  1975 
  1976 	// find out which plugin (if any) was the last to push a TMsgOperation
  1977 	TMsgOperation* currentOperation;
  1978 
  1979 	for (currentOperation = iCurrentOperation ? iCurrentOperation->iPrev : NULL;
  1980 		 currentOperation != NULL;
  1981 		 currentOperation = currentOperation->iPrev)
  1982 			{
  1983 			if (currentOperation->iCurrentPlugin == iCurrentPlugin)
  1984 				return ETrue;
  1985 			}
  1986 
  1987 	return EFalse;
  1988 	}
  1989 
  1990 
  1991 TBool CFsMessageRequest::IsPluginRequest()
  1992 	{
  1993 	if(iOwnerPlugin) // Check the previous operation had a plugin)
  1994 		{
  1995 		return ETrue;
  1996 		}
  1997 	return EFalse;
  1998 	}
  1999 
  2000 
  2001 void CFsClientMessageRequest::Free()
  2002 //
  2003 //
  2004 //
  2005 	{
  2006 	__THRD_PRINT(_L("CFsClientMessageRequest::Free()"));
  2007 	__ASSERT_ALWAYS(CurrentOperationPtr() == NULL, Fault(EFreeingMsgWithMsgOp));
  2008 	if (iPoolSrc)
  2009 		{
  2010 		TParsePool::Release(iPoolSrc);
  2011 		iPoolSrc = 0;
  2012 		}
  2013 
  2014 	if (iPoolDest)
  2015 		{
  2016 		TParsePool::Release(iPoolDest);
  2017 		iPoolDest = 0;
  2018 		}
  2019 
  2020 	SetScratchValue(0);	// this should close the CFsObject
  2021 	iOperation = NULL;
  2022 	RequestAllocator::FreeRequest(this);
  2023 	}
  2024 
  2025 
  2026 TInt CFsClientMessageRequest::AllocParseObjects(const TOperation& aOperation)
  2027 	{
  2028 	__ASSERT_ALWAYS(iPoolSrc == NULL && iPoolDest == NULL, Fault(ETParsePoolGet));
  2029 
  2030 	if (aOperation.iFlags & EParseSrc)
  2031 		{
  2032 		iPoolSrc = TParsePool::Get();
  2033 		if (iPoolSrc == NULL)
  2034 			return KErrNoMemory;
  2035 		}
  2036 	if (aOperation.iFlags & EParseDst)
  2037 		{
  2038 		iPoolDest = TParsePool::Get();
  2039 		if (iPoolDest == NULL)
  2040 			return KErrNoMemory;
  2041 		}
  2042 	return KErrNone;
  2043 	}
  2044 
  2045 TParse& CFsClientMessageRequest::Src()
  2046 //
  2047 //
  2048 	{
  2049 	__ASSERT_ALWAYS(iPoolSrc, Fault(ETParsePoolGet));
  2050 	return (iPoolSrc->GetObject());
  2051 	}
  2052 
  2053 TParse& CFsClientMessageRequest::Dest()
  2054 //
  2055 //
  2056 //
  2057 	{
  2058 	__ASSERT_ALWAYS(iPoolDest, Fault(ETParsePoolGet));
  2059 	return (iPoolDest->GetObject());
  2060 	}
  2061 
  2062 
  2063 
  2064 TParsePool* TParsePool::iFreeHead   = 0;
  2065 TParsePool* TParsePool::iClosedHead = 0;
  2066 TInt        TParsePool::iCountFree  = 0;
  2067 RFastLock	TParsePool::iLock;
  2068 
  2069 
  2070 TParsePool::TParsePool()
  2071 :	iNext   (iFreeHead),
  2072 	iPrev   (0),
  2073 	iFree   (ETrue)
  2074 	{
  2075 	}
  2076 
  2077 TInt TParsePool::Init()
  2078 	{
  2079 	return iLock.CreateLocal();
  2080 	}
  2081 
  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
  2086 	{
  2087 	iLock.Wait();
  2088 
  2089 	TParsePool* pObject = 0;
  2090 
  2091 	// If we don't have anything in the free list, allocate some more...
  2092 	if (iCountFree < 1)
  2093 		{    
  2094 		__ASSERT_DEBUG(iFreeHead == NULL, Fault(ETParsePoolGet));
  2095 		for (TInt i = 0; i < KEBlockSize; i++)
  2096 			{
  2097 			// if allocation fails break out of the loop.
  2098 			pObject = new TParsePool;
  2099 			if (pObject == NULL)
  2100 				break;
  2101 			
  2102 			iCountFree++;
  2103 			
  2104 			if (iFreeHead)
  2105 				iFreeHead->iPrev = pObject;
  2106 
  2107 			iFreeHead = pObject;
  2108 			}
  2109 		}
  2110 
  2111 	// if we failed to allocate even a single object, return NULL
  2112 	if (iCountFree < 1)
  2113 		{
  2114 		iLock.Signal();
  2115 		return NULL;
  2116 		}
  2117 
  2118 
  2119 	__ASSERT_ALWAYS(iFreeHead != NULL, Fault(ETParsePoolGet));
  2120 
  2121 	pObject = iFreeHead;
  2122 	pObject->iFree = EFalse;
  2123 
  2124 
  2125 	// Remove the head of the free list...
  2126 	iFreeHead = pObject->iNext;
  2127 	if (iFreeHead)
  2128 		iFreeHead->iPrev = 0;
  2129 	iCountFree--;
  2130 
  2131 	// ... and add it to the closed list
  2132 	pObject->iNext = iClosedHead;
  2133 	pObject->iPrev = 0;
  2134 	if (iClosedHead)
  2135 		iClosedHead->iPrev = pObject;
  2136 	iClosedHead = pObject;
  2137 
  2138 	iLock.Signal();
  2139 
  2140 	return pObject;
  2141 	}
  2142 
  2143 
  2144 void TParsePool::Release(TParsePool* aObject)
  2145 //
  2146 // Release a sub-sequence of TParsePool objects back to the free list.
  2147 //
  2148 	{
  2149 	__ASSERT_ALWAYS(aObject != NULL && !aObject->iFree, Fault(ETParsePoolGet));
  2150 
  2151 	iLock.Wait();
  2152 
  2153 	aObject->iFree = ETrue;
  2154 
  2155 	// Get the objects either side of the one we're interested in
  2156 	TParsePool* pPrevious = aObject->iPrev;
  2157 	TParsePool* pNext     = aObject->iNext;
  2158 
  2159 	// Remove it from the closed list
  2160 	if (pPrevious)
  2161 		pPrevious->iNext = pNext;
  2162 	else
  2163 		iClosedHead = pNext;
  2164 
  2165 	if (pNext)
  2166 		pNext->iPrev = pPrevious;
  2167 
  2168 
  2169 	// Now add it to the free list
  2170 	aObject->iNext = iFreeHead;
  2171 	aObject->iPrev = 0;
  2172 	if (iFreeHead)
  2173 		iFreeHead->iPrev = aObject;
  2174 
  2175 	iFreeHead = aObject;
  2176 	iCountFree++;
  2177 
  2178 	iLock.Signal();
  2179 	}
  2180 
  2181 
  2182 CFsInternalRequest::CFsInternalRequest()
  2183 //
  2184 //
  2185 //
  2186 	{
  2187 	// iStatus=NULL;
  2188 	// iIsAllocated=EFalse;
  2189 	}
  2190 
  2191 void CFsInternalRequest::Set(const TOperation& aOperation,CSessionFs* aSession)
  2192 //
  2193 //
  2194 // 
  2195 	{
  2196 	CFsRequest::Set(aOperation,aSession);
  2197 	}
  2198 
  2199 void CFsInternalRequest::Process()
  2200 //
  2201 //
  2202 //
  2203 	{
  2204 	__THRD_PRINT(_L("CFsInternalRequest::Process()"));
  2205 	TInt r=KErrNone;
  2206 	TRAPD(leaveValue,r=iOperation->DoRequestL(this));
  2207 	// internal requests should never fail
  2208 	__ASSERT_ALWAYS(leaveValue==KErrNone && (r==KErrNone||r==EReqActionBusy),Fault(EInternalRequestProcess));
  2209 
  2210 	// request postponed ? (e.g. if a page used by file cache is busy).
  2211 	if (r == EReqActionBusy)
  2212 		{
  2213 		Dispatch();
  2214 		return;
  2215 		}
  2216 
  2217 	Complete(r);
  2218 	}
  2219 
  2220 
  2221 void CFsInternalRequest::Complete(TInt aError)
  2222 //
  2223 //
  2224 //
  2225 	{
  2226 	__PRINT1(_L("CFsInternalRequest::Complete() with %d"),aError);
  2227 	TInt func = Operation()->Function();
  2228 	if(func==KCancelSession || func==KCancelPlugin || func==KFlushDirtyData)
  2229 		{
  2230 		__ASSERT_DEBUG(ThreadHandle()!=0 && !FsThreadManager::IsDisconnectThread(),Fault(EInternalRequestComplete1));
  2231 		RThread t;
  2232 		t.SetHandle(ThreadHandle());
  2233 		TRequestStatus* s=&Status();
  2234 		t.RequestComplete(s,aError);
  2235 		Free();
  2236 		}
  2237 	else if(func == KDispatchObjectClose)
  2238 		{
  2239 		TFsCloseObject::Complete(this);
  2240 		Free();
  2241 		}
  2242 	else if(func==KFileShareClose)
  2243 		{
  2244 		if (aError == EReqActionBusy)
  2245 			{
  2246 			Dispatch();
  2247 			}
  2248 		else
  2249 			{
  2250 			TFsCloseFileShare::Complete(this);
  2251 			Free();
  2252 			}
  2253 		}
  2254 	else
  2255 		Fault(EInternalRequestComplete3);
  2256 	}
  2257 
  2258 void CFsInternalRequest::Dispatch()
  2259 //
  2260 //
  2261 //
  2262 	{
  2263 	__THRD_PRINT(_L("CFsInternalRequest::Dispatch()"));
  2264 	__ASSERT_ALWAYS(Initialise()==KErrNone,Fault(EInternalRequestDispatch1));
  2265 
  2266 	if(iCurrentPlugin && Operation()->Function() == KCancelPlugin)
  2267 		{
  2268 		TFsPluginRequest request(this);
  2269 		TInt r = iCurrentPlugin->Deliver(request);
  2270 		__ASSERT_ALWAYS(r == KErrNone, Fault(EInternalRequestDispatchCancelPlugin));
  2271 		}
  2272 	else
  2273 		{
  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);
  2286 		else
  2287 			pT->DeliverFront(this);
  2288 		FsThreadManager::UnlockDrive(drivenumber);
  2289 		}
  2290 	}
  2291 
  2292 void CFsInternalRequest::Free()
  2293 //
  2294 //
  2295 //
  2296 	{
  2297 	__THRD_PRINT1(_L("CFsInternalRequest::Free() isAllocated=%d"),IsAllocated());
  2298 
  2299 	SetScratchValue(0);	// this should close the CFsObject
  2300 
  2301 	if(!IsAllocated())
  2302 		delete(this);
  2303 	}
  2304 
  2305 void CFsDisconnectRequest::Dispatch()
  2306 //
  2307 //
  2308 //
  2309 	{
  2310 	__THRD_PRINT(_L("CFsDisconnectRequest::Dispatch()"));
  2311 	// no need to lock
  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);
  2317 	}
  2318 
  2319 void CFsDisconnectRequest::Process()
  2320 //
  2321 //
  2322 //
  2323 	{
  2324 	__THRD_PRINT(_L("CFsDisconnectRequest::Process()"));
  2325 	TInt r=KErrNone;
  2326 	TRAPD(leaveValue,r=iOperation->DoRequestL(this));
  2327 	leaveValue=leaveValue; // just to make compiler happy
  2328 	__ASSERT_DEBUG(leaveValue==KErrNone && r==KErrNone,Fault(EDisonncectRequestProcess));
  2329 	Complete(r);
  2330 	}
  2331 
  2332 void CFsDisconnectRequest::Complete(TInt aError)
  2333 //
  2334 //
  2335 //
  2336 	{
  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();
  2344 	delete(Session());
  2345 	TheFileServer->SessionQueueLockSignal();
  2346 	// NB Must complete the message AFTER the session has been deleted...
  2347 	Message().Complete(aError);
  2348 	delete(this);	
  2349 	}
  2350 
  2351 
  2352 /**
  2353 Create a new synchronous message scheduler
  2354 */
  2355 CFsSyncMessageScheduler* CFsSyncMessageScheduler::NewL()
  2356 	{
  2357 	__PRINT(_L("CFsSyncMessageScheduler::NewL()"));
  2358 
  2359 	CFsSyncMessageScheduler* pSelf = new(ELeave)CFsSyncMessageScheduler();
  2360 	
  2361 	CleanupStack::PushL(pSelf);
  2362 	pSelf->ConstructL();
  2363 	CleanupStack::Pop();
  2364 	
  2365 	return(pSelf);
  2366 	}
  2367 
  2368 
  2369 /**
  2370 Construct a synchronous message scheduler
  2371 */
  2372 CFsSyncMessageScheduler::CFsSyncMessageScheduler()
  2373  : CActive(EPriorityHigh),
  2374    iList(_FOFF(CFsRequest,iLink))
  2375 	{
  2376 	__PRINT(_L("CFsSyncMessageScheduler::CFsSyncMessageScheduler()"));
  2377 	}
  2378 
  2379 
  2380 /**
  2381 Second-phase constructor
  2382 */
  2383 
  2384 void CFsSyncMessageScheduler::ConstructL()
  2385 	{
  2386 	__PRINT(_L("CFsSyncMessageScheduler::ConstructL()"));
  2387 	
  2388 	User::LeaveIfError(iLock.CreateLocal());
  2389 	User::LeaveIfError(iThread.Open(RThread().Id()));
  2390 	
  2391 	CActiveScheduler::Add(this);
  2392 	}
  2393 	
  2394 	
  2395 /**
  2396 Synchronous message scheduler 
  2397 	- dispatch any synchronous requests that were queued via ::Dispatch
  2398 */
  2399 void CFsSyncMessageScheduler::RunL()
  2400 	{
  2401 	__PRINT(_L(">> CFsSyncMessageScheduler::RunL()"));
  2402 	
  2403 	FOREVER
  2404 		{
  2405 		iLock.Wait();
  2406 		if(iList.IsEmpty())
  2407 			{
  2408 			break;
  2409 			}
  2410 		else
  2411 			{
  2412 			CFsRequest* request = iList.First();
  2413 			request->iLink.Deque();
  2414 			iLock.Signal();
  2415 			__PRINT1(_L("   CFsSyncMessageScheduler - Dispatching message %08x"), request);
  2416 			request->Process();
  2417 			}
  2418 		}
  2419 	
  2420 	iSignalled = EFalse;
  2421 	iStatus = KRequestPending;
  2422 	SetActive();
  2423 	iLock.Signal();
  2424 	
  2425 	__PRINT(_L("<< CFsSyncMessageScheduler::RunL()"));
  2426 	}
  2427 
  2428 
  2429 /**
  2430 DoCancel - Not Implemented
  2431 */
  2432 void CFsSyncMessageScheduler::DoCancel()
  2433 	{
  2434 	__PRINT(_L("CFsSyncMessageScheduler::DoCancel"));
  2435 	}
  2436 
  2437 
  2438 /**
  2439 Queue synchronous requests to be processed in main thread context
  2440 	- called when synchronous messages are passed from plugin threads
  2441 */
  2442 void CFsSyncMessageScheduler::Dispatch(CFsRequest* aRequest)
  2443 	{
  2444 	__PRINT1(_L("CFsSyncMessageScheduler::Dispatch(%08x)"), aRequest);
  2445 
  2446 	// Accquire lock and add request to queue.
  2447 	iLock.Wait();
  2448 	iList.AddFirst(*aRequest);
  2449 
  2450 	if(!iSignalled)
  2451 		{
  2452 		// set iSignalled in case another thread (plug-in) is calling dispatch, then release lock.
  2453 		iSignalled = ETrue;
  2454 		iLock.Signal();
  2455 
  2456 		// signal main thread.
  2457 		TRequestStatus* s = &iStatus;
  2458 		iThread.RequestComplete(s, KErrNone);
  2459 		}
  2460 	else
  2461 		{
  2462 		// main thread already signalled, just release lock.
  2463 		iLock.Signal();
  2464 		}
  2465 	}
  2466 
  2467 
  2468 /**
  2469 Complete outstanding requests for the specified session
  2470 */
  2471 void CFsSyncMessageScheduler::CompleteSessionRequests(CSessionFs* aSession, TInt aValue)
  2472 	{
  2473 	__PRINT2(_L("FsPluginManager::CompleteSessionRequests(%08x, %d)"), aSession, aValue);
  2474 	
  2475 	iLock.Wait();
  2476 	TDblQueIter<CFsRequest> q(iList);
  2477 	CFsRequest* pR;
  2478 	while((pR=q++)!=NULL)
  2479 		{
  2480 		if(pR->Session()==aSession)
  2481 			{
  2482 			pR->iLink.Deque();
  2483 			pR->Complete(aValue);
  2484 			}
  2485 		}
  2486 	iLock.Signal();
  2487 	}
  2488