userlibandfileserver/fileserver/sfile/sf_notifier.cpp
changeset 0 a41df078684a
child 31 56f325a607ea
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2008-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_notifier.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "sf_notifier.h"
       
    19 #include "sf_file_cache.h"
       
    20 
       
    21 CFsObjectCon* FsNotificationManager::iNotifyRequests = NULL;
       
    22 RFastLock FsNotificationManager::iChainLock;
       
    23 TInt FsNotificationManager::iFilterRegister[];
       
    24 CFsPool<CFsNotificationBlock>* FsNotificationManager::iPool;
       
    25 
       
    26 
       
    27 CFsNotificationPathFilter* CFsNotificationPathFilter::NewL(const TDesC& aPath, const TDesC& aFilename)
       
    28 	{
       
    29 	CFsNotificationPathFilter* self = new (ELeave) CFsNotificationPathFilter();
       
    30 	CleanupStack::PushL(self);
       
    31 	self->ConstructL(aPath,aFilename);
       
    32 	CleanupStack::Pop(self);
       
    33 	return self;
       
    34 	}
       
    35 
       
    36 void CFsNotificationPathFilter::ConstructL(const TDesC& aPath, const TDesC& aFilename)
       
    37 	{
       
    38 	//Allocate the path and filename
       
    39 	iPath = aPath.AllocL();
       
    40 	iFilename = aFilename.AllocL();	
       
    41 	}
       
    42 
       
    43 CFsNotificationPathFilter::~CFsNotificationPathFilter()
       
    44 	{
       
    45 	if(iFilename)
       
    46 		delete iFilename;
       
    47 	if(iPath)
       
    48 		delete iPath;
       
    49 	}
       
    50 
       
    51 CFsNotificationPathFilter::CFsNotificationPathFilter()
       
    52 : iPath(NULL), iFilename(NULL)
       
    53 	{
       
    54 	}
       
    55 
       
    56 CFsNotifyRequest* CFsNotifyRequest::NewL()
       
    57 	{
       
    58 	CFsNotifyRequest* self = new(ELeave) CFsNotifyRequest();
       
    59 	CleanupStack::PushL(self);
       
    60 	self->ConstructL();
       
    61 	CleanupStack::Pop();
       
    62 	return self;
       
    63 	}
       
    64 
       
    65 void CFsNotifyRequest::ConstructL()
       
    66 	{
       
    67 	User::LeaveIfError(iClientSyncLock.CreateLocal());
       
    68 	User::LeaveIfError(iTailSemaphore.CreateLocal()); 
       
    69 	}
       
    70 
       
    71 CFsNotifyRequest::CFsNotifyRequest()
       
    72 	{
       
    73 	SetActive(EInactive);
       
    74 	}
       
    75 
       
    76 CFsNotifyRequest::~CFsNotifyRequest()
       
    77 	{
       
    78 	__PRINT(_L("CFsNotifyRequest::~CFsNotifyRequest()"));
       
    79 	
       
    80 	RemoveFilters();
       
    81 	
       
    82 	if(ClientMsgHandle()!=0)
       
    83 		iClientMsg.Complete(KErrCancel);
       
    84 	
       
    85 	if(iBufferMsg.Handle()!=0)
       
    86 		iBufferMsg.Complete(KErrCancel);
       
    87 	
       
    88 	iClientSyncLock.Close();
       
    89 	iTailSemaphore.Close();
       
    90 	}
       
    91 
       
    92 /*
       
    93  * Returns the Array of TypeFilters.
       
    94  * Each TFsNotificationTypeFilter matches to a particular TFsNotification::TFsNotificationType
       
    95  * and has a CFsNotificationFilter which stores the iPath and iName associated with this filter type.
       
    96  * 
       
    97  * (These are speerated so that we can have multiple type filters for every name filter)
       
    98  */
       
    99 TFsNotificationTypeArray* CFsNotifyRequest::FilterTypeList(TInt aDrive,TInt aIndex)
       
   100 	{
       
   101 	__ASSERT_DEBUG(aIndex < KNumRegisterableFilters,Fault(ENotificationFault));
       
   102 
       
   103 	TFsNotificationTypeDriveArray* filters = iDrivesTypesFiltersMap.Find(aDrive);
       
   104 	if(filters)
       
   105 		return &((*filters)[aIndex]);
       
   106 	else
       
   107 		return NULL;
       
   108 	}
       
   109 
       
   110 //Sets filter's notification request status
       
   111 void CFsNotifyRequest::SetActive(TNotifyRequestStatus aValue)
       
   112 	{
       
   113 	iNotifyRequestStatus = aValue;
       
   114 	}
       
   115 
       
   116 CFsNotifyRequest::TNotifyRequestStatus CFsNotifyRequest::ActiveStatus()
       
   117 	{
       
   118 	return (TNotifyRequestStatus)iNotifyRequestStatus;
       
   119 	}
       
   120 
       
   121 //Completes and frees notification request
       
   122 //In case of KErrNone must be called with iChainLock already held
       
   123 void CFsNotifyRequest::CompleteClientRequest(TInt aReason,TBool aIsCancel)
       
   124 	{
       
   125 	__PRINT(_L("CFsNotifyRequest::CompleteClientRequest()"));
       
   126 
       
   127 	iClientSyncLock.Wait();
       
   128 	
       
   129 	if(aReason==KErrNone) 
       
   130 		{
       
   131 		__PRINT(_L("CFsNotifyRequest::CompleteClientRequest() - Complete KErrNone"));
       
   132 		//Synchronising the current iServerTail to the client.
       
   133 		iClientHead = iClientTail; //Client has read all previous entries
       
   134 		iClientTail = iServerTail; //Client's new tail is everything the server has been writing since this function was last called
       
   135 		TInt clientTail = iClientTail;
       
   136 		TPckg<TInt> tailDes(clientTail);
       
   137 		iClientMsg.Write(KMsgPtr0,tailDes);
       
   138 		}
       
   139 	else if(aIsCancel)
       
   140 		{
       
   141 		__PRINT(_L("CFsNotifyRequest::CompleteClientRequest() - Complete isCancel"));
       
   142 		iServerTail = 0;
       
   143 		iClientTail = 0;
       
   144 		iClientHead = 0;
       
   145 		TPckgBuf<TInt> tailDes(iClientTail);
       
   146 		//Perhaps client has crashed so no point checking return:
       
   147 		iClientMsg.Write(KMsgPtr0,tailDes); 
       
   148 		}
       
   149 	__PRINT(_L("CFsNotifyRequest::CompleteClientRequest() - Complete Request"));
       
   150 	iClientMsg.Complete(aReason);
       
   151 	iClientSyncLock.Signal();
       
   152 	}
       
   153 	
       
   154 TInt CFsNotifyRequest::SynchroniseBuffer(CFsNotificationBlock& aBlock,TInt aServerTail, TInt aNotificationSize)
       
   155 	{
       
   156 	TPtrC8 blockDes((TText8*)aBlock.Data(),aNotificationSize);
       
   157 	return iBufferMsg.Write(KMsgPtr0,blockDes,aServerTail);
       
   158 	}
       
   159 
       
   160 //Removes all filters.
       
   161 //Deletes iPath, iFilename
       
   162 TInt CFsNotifyRequest::RemoveFilters()
       
   163 	{
       
   164 	__PRINT(_L("CFsNotifyRequest::RemoveFilters()"));
       
   165 		
       
   166 	//For every drive with filters set...
       
   167 	RHashMap<TInt,TFsNotificationTypeDriveArray>::TIter iterator(iDrivesTypesFiltersMap);
       
   168 	TFsNotificationTypeDriveArray* currentDriveFilters = (TFsNotificationTypeDriveArray*)iterator.NextValue();
       
   169 	while(currentDriveFilters)
       
   170 		{
       
   171 		//For every filter array (1 for each type of TFsNotificationType)
       
   172 		for(TInt filterType = 0; filterType < KNumRegisterableFilters; filterType++)
       
   173 			{
       
   174 			TFsNotificationTypeArray& filterList = (*currentDriveFilters)[filterType];
       
   175 			TInt filterTypeCount = filterList.Count();
       
   176 			if(filterTypeCount)
       
   177 				{
       
   178 				//Remove this type from the filter register
       
   179 				TFsNotification::TFsNotificationType type = FsNotificationHelper::NotificationType(filterType);
       
   180 				FsNotificationManager::SetFilterRegister(type,EFalse,filterTypeCount);
       
   181 				}
       
   182 			filterList.Reset();
       
   183 			filterList.Close();
       
   184 			}
       
   185 		currentDriveFilters->Reset();
       
   186 		currentDriveFilters->Close();
       
   187 		iterator.RemoveCurrent();
       
   188 		currentDriveFilters = (TFsNotificationTypeDriveArray*)iterator.NextValue();
       
   189 		}
       
   190 	iDrivesTypesFiltersMap.Close();
       
   191 	iPathFilterList.ResetAndDestroy();
       
   192 	iPathFilterList.Close();
       
   193 	return KErrNone;
       
   194 	}
       
   195 
       
   196 TInt CFsNotifyRequest::AddFilterL(CFsNotificationPathFilter* aFilter, TUint aMask)
       
   197 	{
       
   198 	__PRINT(_L("CFsNotifyRequest::AddFilterL"));
       
   199 
       
   200 	iPathFilterList.AppendL(aFilter);
       
   201 	
       
   202 	//Get the drive number to so know which drive array to add the filter(s) to.
       
   203 	TInt driveNum = FsNotificationHelper::DriveNumber(aFilter->iPath->Des()); 
       
   204 	
       
   205 	TInt notifyType = 1; 
       
   206 	TInt r = KErrNone;
       
   207 	//Create/Add a TypeFilter for each type in aMask
       
   208 	while((notifyType & KNotificationValidFiltersMask) && (aMask & KNotificationValidFiltersMask))
       
   209 		{
       
   210 		//If this notifyType is present in aMask
       
   211 		if(aMask & notifyType)
       
   212 			{
       
   213 			TFsNotificationTypeFilter typeFilter;
       
   214 			typeFilter.iNotificationType = (TFsNotification::TFsNotificationType) notifyType;
       
   215 			typeFilter.iPathFilter = aFilter;
       
   216 			TInt index = FsNotificationHelper::TypeToIndex(typeFilter.iNotificationType);
       
   217 			
       
   218 			//If the per-drive-filterLists have not
       
   219 			//been set up yet then do so now.
       
   220 			TFsNotificationTypeDriveArray* driveArray = iDrivesTypesFiltersMap.Find(driveNum);
       
   221 			if(!driveArray)
       
   222 				{
       
   223 				TFsNotificationTypeDriveArray dArray;
       
   224 				r = iDrivesTypesFiltersMap.Insert(driveNum,dArray);
       
   225 				User::LeaveIfError(r);					
       
   226 				driveArray = iDrivesTypesFiltersMap.Find(driveNum);
       
   227 				
       
   228 				//Create filter arrays for every type
       
   229 				for(TInt i =0; i< KNumRegisterableFilters; i++)
       
   230 					{
       
   231 					TFsNotificationTypeArray filterArray;
       
   232 					driveArray->Append(filterArray);
       
   233 					}
       
   234 				}
       
   235 			TFsNotificationTypeArray& filterArray= (*driveArray)[index];
       
   236 			filterArray.Append(typeFilter);
       
   237 
       
   238 			//Remove this type from our mask
       
   239 			//and continue
       
   240 			aMask ^= notifyType;
       
   241 			}
       
   242 		notifyType <<= 1;
       
   243 		}
       
   244 	return r;
       
   245 	}
       
   246 
       
   247 TInt CFsNotifyRequest::SetClientMessage(const RMessage2& aClientMsg)
       
   248 	{
       
   249 	__PRINT(_L("CFsNotifyRequest::SetClientMessage"));
       
   250 	iClientMsg = aClientMsg;
       
   251 	return KErrNone;
       
   252 	}
       
   253 
       
   254 TInt CFsNotifyRequest::ClientMsgHandle()
       
   255 	{
       
   256 	return iClientMsg.Handle();
       
   257 	}
       
   258 
       
   259 void CFsNotifyRequest::CloseNotification()
       
   260 	{
       
   261 	__PRINT(_L("CFsNotifyRequest::CloseNotification()"));
       
   262 	iBufferMsg.Complete(KErrNone);
       
   263 	if(ClientMsgHandle()!=0)
       
   264 		CompleteClientRequest(KErrCancel,EFalse);
       
   265 	}
       
   266 
       
   267 //New notification request from client
       
   268 void FsNotificationManager::AddNotificationRequestL(CFsNotifyRequest* aNotificationRequest)
       
   269 	{
       
   270 	__PRINT(_L("FsNotificationManager::AddNotificationRequestL"));
       
   271 	Lock();
       
   272 	iNotifyRequests->AddL(aNotificationRequest,ETrue);
       
   273 	Unlock();
       
   274 	}
       
   275 
       
   276 //Notification request cancelled
       
   277 //Must be called with iChainLock held
       
   278 void FsNotificationManager::RemoveNotificationRequest(CFsNotifyRequest* aNotificationRequest)
       
   279 	{
       
   280 	__PRINT(_L("FsNotificationManager::RemoveNotificationRequest"));
       
   281 	iNotifyRequests->Remove(aNotificationRequest,ETrue);
       
   282 	}
       
   283 
       
   284 void FsNotificationManager::RemoveNotificationRequest(CSessionFs* aSession)
       
   285 	{
       
   286 	__PRINT(_L("FsNotificationManager::RemoveNotificationRequest(CSessionFs*)"));
       
   287 	
       
   288 	TInt count = Count();
       
   289 	if(count)
       
   290 		{
       
   291 		Lock();
       
   292 		count = Count(); //check again just incase it's changed before we got the lock
       
   293 		if(count)
       
   294 			{
       
   295 			for(TInt i=0; i < count; i++)
       
   296 				{
       
   297 				//Remove all notification requests associated with this session.
       
   298 				CFsNotifyRequest* notify = (CFsNotifyRequest*)(*iNotifyRequests)[i];
       
   299 				if(notify->iSession == aSession)
       
   300 					{
       
   301 					RemoveNotificationRequest(notify);
       
   302 					delete notify;
       
   303 					}
       
   304 				}
       
   305 			if(!Count())
       
   306 				{
       
   307 				__PRINT(_L("FsNotificationManager::RemoveNotificationRequest(CSessionFs*) - Closing Manager"));
       
   308 				Close();
       
   309 				}
       
   310 			}
       
   311 		Unlock();
       
   312 		}
       
   313 	}
       
   314 
       
   315 TBool FsNotificationManager::IsInitialised()
       
   316 	{
       
   317 	__PRINT(_L("FsNotificationManager::IsInitialised()"));
       
   318 	return (TBool)iNotifyRequests;
       
   319 	}
       
   320 
       
   321 void FsNotificationManager::OpenL()
       
   322 	{
       
   323 	__PRINT(_L("FsNotificationManager::InitialiseL()"));
       
   324 	if(!iNotifyRequests)
       
   325 		{
       
   326 		if(iChainLock.Handle() == 0)
       
   327 			{
       
   328 			User::LeaveIfError(iChainLock.CreateLocal());	
       
   329 			}
       
   330 		iNotifyRequests = TheContainer->CreateL();
       
   331 		iPool = CFsPool<CFsNotificationBlock>::New(KNotificationPoolSize);
       
   332 		User::LeaveIfNull(iPool);
       
   333 		}
       
   334 	}
       
   335 
       
   336 void FsNotificationManager::SetFilterRegister(TUint aFilter, TBool aAdd, TInt aCount)
       
   337 	{
       
   338 	__PRINT2(_L("FsNotificationManager::SetFilterRegister(aFilter=%u,aAdd=%d)"),aFilter,aAdd);
       
   339 	TInt index = FsNotificationHelper::TypeToIndex((TFsNotification::TFsNotificationType)aFilter);
       
   340 	TInt& fr = FsNotificationManager::FilterRegister(index);
       
   341 	__ASSERT_DEBUG((aAdd) ? fr >= 0 : fr > 0,Fault(ENotificationFault));
       
   342 	fr+= aAdd ? aCount : -aCount; 
       
   343 	}
       
   344 
       
   345 void FsNotificationManager::SetFilterRegisterMask(TUint aMask,TBool aAdd)
       
   346 	{
       
   347 	__PRINT(_L("FsNotificationManager::RegisterFilterMask()"));
       
   348 	TInt notifyType = 1; 
       
   349 
       
   350 	while(notifyType & KNotificationValidFiltersMask && aMask & KNotificationValidFiltersMask)
       
   351 		{
       
   352 		if(aMask & notifyType)
       
   353 			{
       
   354 			SetFilterRegister(notifyType,aAdd);
       
   355 			aMask ^= notifyType;
       
   356 			}
       
   357 		notifyType <<= 1;
       
   358 		}
       
   359 	}
       
   360 
       
   361 TInt& FsNotificationManager::FilterRegister(TInt aIndex)
       
   362 	{
       
   363 	__PRINT(_L("FsNotificationManager::FilterRegister()"));
       
   364 	__ASSERT_DEBUG(aIndex < KNumRegisterableFilters,Fault(ENotificationFault));
       
   365 	return iFilterRegister[aIndex];
       
   366 	}
       
   367 
       
   368 //Must be called with the iChainLock
       
   369 void FsNotificationManager::Close()
       
   370 	{
       
   371 	__PRINT(_L("FsNotificationManager::Stop()"));
       
   372 	CFsObjectCon*& request = iNotifyRequests;
       
   373 	if(request)
       
   374 		{
       
   375 		TheContainer->Delete(request);
       
   376 		delete iPool;
       
   377 		iPool = NULL;
       
   378 		}
       
   379 	request = NULL;
       
   380 	}
       
   381 
       
   382 TInt FsNotificationManager::Count()
       
   383 	{
       
   384 	__PRINT(_L("FsNotificationManager::Count()"));
       
   385 	if(IsInitialised())
       
   386 		return iNotifyRequests->Count();
       
   387 	return 0;
       
   388 	}
       
   389 
       
   390 void FsNotificationManager::Lock()
       
   391 	{
       
   392 	__PRINT(_L("--->FsNotificationManager::Lock()"));
       
   393 	iChainLock.Wait();
       
   394 	}
       
   395 
       
   396 void FsNotificationManager::Unlock()
       
   397 	{
       
   398 	__PRINT(_L("<---FsNotificationManager::Unlock()"));
       
   399 	iChainLock.Signal();
       
   400 	}
       
   401 
       
   402 //Get the notification type based on the TFsMessage function
       
   403 void FsNotificationHelper::NotificationType(TInt aFunction,TFsNotification::TFsNotificationType& aNotificationType)
       
   404 	{
       
   405 	__PRINT(_L("FsNotificationHelper::NotificationType"));
       
   406 	switch(aFunction)
       
   407 		{
       
   408 		case EFsFileWrite:
       
   409 		case EFsFileWriteDirty:
       
   410 		case EFsFileSetSize:
       
   411 			{
       
   412 			aNotificationType = TFsNotification::EFileChange;
       
   413 			break;
       
   414 			}
       
   415 		case EFsRename:
       
   416 		case EFsFileRename:
       
   417 		case EFsReplace:
       
   418 			{
       
   419 			aNotificationType = TFsNotification::ERename;
       
   420 			break;
       
   421 			}
       
   422 		case EFsMkDir:
       
   423 		case EFsFileCreate:
       
   424 		case EFsFileReplace:
       
   425 			{
       
   426 			aNotificationType = TFsNotification::ECreate;
       
   427 			break;
       
   428 			}
       
   429 		case EFsFileSetAtt:
       
   430 		case EFsFileSet:
       
   431 		case EFsSetEntry:
       
   432 			{
       
   433 			aNotificationType = TFsNotification::EAttribute;
       
   434 			break;
       
   435 			}
       
   436 		case EFsDelete:
       
   437 		case EFsRmDir:
       
   438 			{
       
   439 			aNotificationType = TFsNotification::EDelete;
       
   440 			break;
       
   441 			}
       
   442 		case EFsSetVolume:
       
   443 			{
       
   444 			aNotificationType = TFsNotification::EVolumeName;
       
   445 			break;
       
   446 			}
       
   447 		case EFsSetDriveName:
       
   448 			{
       
   449 			aNotificationType = TFsNotification::EDriveName;
       
   450 			break;
       
   451 			}
       
   452 		case EFsDismountFileSystem:
       
   453 		case EFsMountFileSystem:
       
   454 		case EFsFormatNext:
       
   455 		case EFsRawDiskWrite:
       
   456 		case EFsMountFileSystemScan:
       
   457 			{
       
   458 			aNotificationType = TFsNotification::EMediaChange;
       
   459 			break;
       
   460 			}
       
   461 		default:
       
   462 			{
       
   463 			aNotificationType = (TFsNotification::TFsNotificationType)0;
       
   464 			break;
       
   465 			}
       
   466 		}
       
   467 	}
       
   468 
       
   469 //=====CFsNotificationBlock============================
       
   470 // Uses CFsPool
       
   471 
       
   472 CFsNotificationBlock* CFsNotificationBlock::New()
       
   473 	{
       
   474 	return new CFsNotificationBlock();
       
   475 	}
       
   476 CFsNotificationBlock::CFsNotificationBlock()
       
   477 	{
       
   478 	}
       
   479 CFsNotificationBlock::~CFsNotificationBlock()
       
   480 	{
       
   481 	//Nothing to do here
       
   482 	}
       
   483 TAny* CFsNotificationBlock::Data()
       
   484 	{
       
   485 	return (TAny*)&iData;
       
   486 	}
       
   487 
       
   488 
       
   489 //=====FsNotificationManager===========================
       
   490  
       
   491 //Get the path of the file, folder or drive name based on the TFsMessage function
       
   492 void FsNotificationHelper::PathName(CFsClientMessageRequest& aRequest, TDes& aPath)
       
   493 	{
       
   494 	__PRINT(_L("FsNotificationHelper::PathName"));
       
   495 	//Get the notification type
       
   496 	TInt function = aRequest.Operation()->Function();
       
   497 	
       
   498 	//Get the filename(s)
       
   499 	switch(function)
       
   500 		{
       
   501 		case EFsFileWrite:			//EParseSrc | EFileShare
       
   502 		case EFsFileSetSize:		//EParseSrc | EFileShare
       
   503 		case EFsFileSetAtt:			//EParseDst | EParseSrc, - should not use these; has share.
       
   504 		case EFsFileSet:
       
   505 		case EFsFileWriteDirty:		//EFileShare
       
   506 			{
       
   507 			CFileShare* share = NULL;
       
   508 			CFileCB* file = NULL;
       
   509 			GetFileFromScratch(&aRequest,share,file);	
       
   510 			aPath.Append(file->DriveNumber() + 'A');
       
   511 			aPath.Append(':');
       
   512 			aPath.Append(file->FileName().Des());
       
   513 			break;
       
   514 			}
       
   515 		case EFsFileCreate:			//EParseSrc
       
   516 		case EFsDelete:				//EParseSrc
       
   517 		case EFsSetEntry:			//EParseSrc,
       
   518 		case EFsFileRename:			//EParseDst | EParseSrc,
       
   519 		case EFsRename:				//EParseDst | EParseSrc,
       
   520 		case EFsReplace:			//EParseDst | EParseSrc,
       
   521 		case EFsFileReplace:		//EParseSrc
       
   522 			{
       
   523 			aPath.Copy(aRequest.Src().FullName());
       
   524 			break;
       
   525 			}
       
   526         case EFsRmDir:              //EParseSrc
       
   527         case EFsMkDir:              //EParseSrc
       
   528             {
       
   529             aPath.Copy(aRequest.Src().DriveAndPath());
       
   530             break;
       
   531             }
       
   532 		case EFsFormatNext:			//EParseSrc
       
   533 		case EFsDismountFileSystem: //0
       
   534 		case EFsMountFileSystem:	//0
       
   535 		case EFsSetVolume:			//0
       
   536 		case EFsSetDriveName:		//ESync
       
   537 		case EFsRawDiskWrite:		//EParseSrc
       
   538 		case EFsMountFileSystemScan:
       
   539 			{
       
   540 			_LIT(KFormatDrive,"?:");
       
   541 			TBuf<2> drive;
       
   542 			drive.Append(KFormatDrive);
       
   543 			drive[0] = TText(aRequest.Drive()->DriveNumber() + 'A');
       
   544 			aPath.Copy(drive);
       
   545 			break;
       
   546 			}
       
   547 		default:
       
   548 			ASSERT(0);
       
   549 			break;
       
   550 		}
       
   551 	}
       
   552 
       
   553 //Get the new path of the file, folder or drive name based on the TFsMessage function
       
   554 void FsNotificationHelper::NewPathName(CFsClientMessageRequest& aRequest, TPtrC& aNewPath)
       
   555 	{
       
   556 	__PRINT(_L("FsNotificationHelper::NewPathName"));
       
   557 	//Get the notification type
       
   558 	TInt function = aRequest.Operation()->Function();
       
   559 
       
   560 	//Get the filename(s)
       
   561 	switch(function)
       
   562 		{
       
   563 		case EFsFileRename:			//EParseDst | EParseSrc,
       
   564 		case EFsRename:				//EParseDst | EParseSrc,
       
   565 		case EFsReplace:			//EParseDst | EParseSrc,
       
   566 			{
       
   567 			aNewPath.Set(aRequest.Dest().FullName());
       
   568 			break;
       
   569 			}
       
   570 		case EFsSetDriveName:		//ESync
       
   571 			{
       
   572 			TFileName name;
       
   573 			aRequest.ReadL(KMsgPtr1, name);
       
   574 			aNewPath.Set(name);
       
   575 			break;
       
   576 			}
       
   577 		case EFsSetVolume:			//0
       
   578 			{
       
   579 			TFileName name;
       
   580 			aRequest.ReadL(KMsgPtr0, name);
       
   581 			aNewPath.Set(name);
       
   582 			break;
       
   583 			}
       
   584 		default:
       
   585 			{
       
   586 			ASSERT(0);
       
   587 			break;
       
   588 			}
       
   589 		}
       
   590 	}
       
   591 
       
   592 //Get the size of the notification based on its type
       
   593 TInt FsNotificationHelper::NotificationSize(CFsClientMessageRequest& aRequest, TFsNotification::TFsNotificationType aNotificationType, const TDesC& aName)
       
   594 	{
       
   595 	__PRINT(_L("FsNotificationHelper::NotificationSize"));
       
   596 	
       
   597 	/*
       
   598 	 * If there are no new names, the order of the data in the buffer is:
       
   599 	 * Word1   : NotificationSize (2 bytes) , PathSize (2 bytes)
       
   600 	 * Word2   : NotificationType (Lower 2 bytes)
       
   601 	 * Word(s) : Path (TText8) , [Any sub-class members]
       
   602 	 * 
       
   603 	 * Else for notification types ERename, EVolumeName and EDriveName the order is:
       
   604 	 * Word1   : NotificationSize (2 bytes) , PathSize (2 bytes)
       
   605 	 * Word2   : NewNameSize (2 bytes) , NotificationType (2 bytes)
       
   606 	 * Word(s) : Path (TText8) , NewName (TText8)
       
   607 	 * 
       
   608 	 * EOverflow size: KNotificationHeaderSize
       
   609 	 */	
       
   610 	
       
   611 	TInt size = KNotificationHeaderSize + Align4(aName.Size());
       
   612 	
       
   613 	switch(aNotificationType)
       
   614 		{
       
   615 		//NewName
       
   616  		case TFsNotification::ERename:
       
   617 		case TFsNotification::EVolumeName:
       
   618 		case TFsNotification::EDriveName:
       
   619 			{
       
   620 			TPtrC dest;
       
   621 			NewPathName(aRequest,dest);
       
   622 			size += Align4(dest.Size()); 
       
   623 			break;
       
   624 			}
       
   625 		case TFsNotification::EFileChange:
       
   626 			{
       
   627 			size += sizeof(TInt64);
       
   628 			break;
       
   629 			}
       
   630 		case TFsNotification::EAttribute:
       
   631 			{
       
   632 			size += sizeof(TUint64);
       
   633 			break;
       
   634 			}
       
   635 		case TFsNotification::ECreate: 
       
   636 		case TFsNotification::EDelete:
       
   637 		case TFsNotification::EMediaChange:
       
   638 			{
       
   639 			break;
       
   640 			}
       
   641 		default:
       
   642 			{
       
   643 			ASSERT(0);
       
   644 			break;
       
   645 			}
       
   646 		}
       
   647 	return (TUint16) size;
       
   648 	}
       
   649 
       
   650 TFsNotification::TFsNotificationType FsNotificationHelper::NotificationType(TInt& aIndex)
       
   651 	{
       
   652 	__PRINT(_L("FsNotificationHelper::NotificationType(TInt)"));
       
   653 	__ASSERT_DEBUG(aIndex < KNumRegisterableFilters, Fault(ENotificationFault));
       
   654 	
       
   655 	switch(aIndex) //No break statements here on purpose
       
   656 		{
       
   657 		case 7 : return TFsNotification::EMediaChange;
       
   658 		case 6 : return TFsNotification::EDriveName;
       
   659 		case 5 : return TFsNotification::EVolumeName;
       
   660 		case 4 : return TFsNotification::EDelete;
       
   661 		case 3 : return TFsNotification::EAttribute;
       
   662 		case 2 : return TFsNotification::ECreate;
       
   663 		case 1 : return TFsNotification::ERename;
       
   664 		case 0 : return TFsNotification::EFileChange;
       
   665 		default: ASSERT(0); return (TFsNotification::TFsNotificationType) 0;
       
   666 		}
       
   667 	}
       
   668 
       
   669 //Get the array index of the notification based on its type
       
   670 TInt FsNotificationHelper::TypeToIndex(TFsNotification::TFsNotificationType aType)
       
   671 	{
       
   672 	__PRINT(_L("FsNotificationHelper::ArrayIndex"));
       
   673 
       
   674 	TInt index = 0; 
       
   675 	switch(aType) //No break statements here on purpose
       
   676 		{
       
   677 		case TFsNotification::EMediaChange: index++;
       
   678 		case TFsNotification::EDriveName:	index++;
       
   679 		case TFsNotification::EVolumeName:	index++;
       
   680 		case TFsNotification::EDelete:	 	index++;
       
   681 		case TFsNotification::EAttribute:	index++;
       
   682 		case TFsNotification::ECreate:	 	index++;
       
   683 		case TFsNotification::ERename:	 	index++;
       
   684 		case TFsNotification::EFileChange:	// skip;
       
   685 		default: break;
       
   686 		}
       
   687 	__ASSERT_DEBUG(index < KNumRegisterableFilters, Fault(ENotificationFault));
       
   688 	return index;
       
   689 	}
       
   690 
       
   691 TInt FsNotificationHelper::DriveNumber(const TPtrC& aPath)
       
   692 	{
       
   693 	if(aPath.Length() >= 2 && ((TChar)aPath[1])==(TChar)':')
       
   694 		{
       
   695 		TChar driveChar = ((TChar)aPath[0]);
       
   696 		driveChar.UpperCase();
       
   697 		TInt driveNum = driveChar-(TChar)'A'; 
       
   698 		return driveNum;
       
   699 		}
       
   700 	else
       
   701 		{
       
   702 		return KErrNotFound;
       
   703 		}
       
   704 	}
       
   705 
       
   706 //Get the attributes set and cleared
       
   707 void FsNotificationHelper::Attributes(CFsClientMessageRequest& aRequest, TUint& aSet, TUint& aClear)
       
   708 	{
       
   709 	__PRINT(_L("FsNotificationHelper::Attributes"));
       
   710 
       
   711 	TInt function = aRequest.Operation()->Function();
       
   712 	const RMessage2& msg = aRequest.Message();
       
   713 
       
   714 	switch(function)
       
   715 		{
       
   716 		case EFsFileSet:
       
   717 			{
       
   718 			aSet = msg.Int1();
       
   719 			aClear = msg.Int2();
       
   720 			break;
       
   721 			}
       
   722 		case EFsFileSetAtt:
       
   723 			{
       
   724 			aSet = msg.Int0();
       
   725 			aClear = msg.Int1();
       
   726 			break;
       
   727 			}
       
   728 		case EFsSetEntry:
       
   729 			{
       
   730 			aSet = msg.Int2();
       
   731 			aClear = msg.Int3();
       
   732 			break;
       
   733 			}
       
   734 		default:
       
   735 			{
       
   736 			ASSERT(0);
       
   737 			break;
       
   738 			}
       
   739 		}
       
   740 	}
       
   741 
       
   742 
       
   743 TBool CFsNotifyRequest::ValidateNotification(TInt aNotificationSize, TInt& aServerTail)
       
   744 	{
       
   745 	__PRINT(_L("CFsNotifyRequest::ValidateNotification"));
       
   746 	//RDebug::Print(_L("CFsNotifyRequest::ValidateNotification - iServerTail=%d, aServerTail=%d, iClientTail=%d,iClientHead=%d, aNotificationSize=%d"),iServerTail,aServerTail,iClientTail,iClientHead,aNotificationSize);
       
   747 	//
       
   748 	//Start Validation
       
   749 	//
       
   750 	TBool overflow = EFalse;
       
   751 	
       
   752 	//Check that we have not filled the buffer
       
   753 	//Also if iClientMsg is present this is the first notification
       
   754 	if (aServerTail == iClientHead && ClientMsgHandle()==0)
       
   755 		{
       
   756 		//Overflow
       
   757 		overflow = ETrue;
       
   758 		return overflow;
       
   759 		}
       
   760 
       
   761 	//Work out remaining size taking account of whether the end position is
       
   762 	//before or after the overflow position.
       
   763 	TInt remainingSize = (iClientHead > aServerTail)
       
   764 			? iClientHead - aServerTail 
       
   765 			: iClientBufferSize - (aServerTail - iClientHead);
       
   766 	
       
   767 	//In order to ensure that we can always fit in an overflow notification,
       
   768 	//Remove the size of an overflow notification from the total free space in the buffer
       
   769 	remainingSize -= KNotificationHeaderSize;
       
   770 
       
   771 	//Check whether there is any chance of this notification fitting in the buffer
       
   772 	if (aNotificationSize > remainingSize)
       
   773 		{
       
   774 		//Overflow
       
   775 		overflow = ETrue;
       
   776 		}
       
   777 	//Check that the notification fits in a contiguous chunk.
       
   778 	//If we've wrapped around already..
       
   779 	else if (iClientHead > aServerTail)
       
   780 		{
       
   781 		//Does it fit?
       
   782 		if ((iClientHead - aServerTail) < aNotificationSize)
       
   783 			{
       
   784 			//Overflow
       
   785 			overflow = ETrue;
       
   786 			}
       
   787 		}
       
   788 	//Else, We've not wrapped around yet.
       
   789 	//Does it fit at the end?
       
   790 	else if ((iClientBufferSize - aServerTail) < aNotificationSize)
       
   791 		{
       
   792 		//Notification won't fit in the space at the end of the buffer
       
   793 		//Fill end of buffer with KNotificationBufferFiller (if we're not at the very end already)
       
   794 		if(iServerTail != iClientBufferSize)
       
   795 			{
       
   796 			//If there is any dead space it should always be at least 1 word big
       
   797 			TPtrC8 fillerDes((TText8*) &KNotificationBufferFiller, sizeof(TUint));
       
   798 			iBufferMsg.Write(KMsgPtr0, fillerDes, aServerTail);
       
   799 			}
       
   800 
       
   801 		//It doesn't fit at the end,
       
   802 		//does it fit at the beginning?
       
   803 		if (iClientHead < aNotificationSize)
       
   804 			{
       
   805 			//Overflow
       
   806 			overflow = ETrue;
       
   807 			}
       
   808 		//Notification would fit at the beginning...		
       
   809 		else
       
   810 			{
       
   811 			//...however we need to ensure that there is
       
   812 			//still space for overflow next time.
       
   813 			if ((iClientHead - aNotificationSize) < KNotificationHeaderSize)
       
   814 				{
       
   815 				overflow = ETrue;
       
   816 				}
       
   817 			else
       
   818 				{
       
   819 				//Everything was ok, update aServerTail
       
   820 				aServerTail = 0;
       
   821 				}
       
   822 			}
       
   823 		}	
       
   824 
       
   825 	//
       
   826 	//End Validation
       
   827 	//
       
   828 	return overflow;
       
   829 	}
       
   830 
       
   831 // Called from FsNotificationManager::HandleChange().
       
   832 // Sends notifications into the client's buffer.
       
   833 // If there is a iClientMsg then this is the first time this
       
   834 // has been called since the client called RequestNotifications.
       
   835 // In this situation we complete the client request.
       
   836 TInt CFsNotifyRequest::NotifyChange(CFsClientMessageRequest* aRequest,const TDesC& aName, TFsNotification::TFsNotificationType aNotificationType, CFsNotificationBlock& aBlock)
       
   837 	{
       
   838 	/*
       
   839 	 * Different notification types have different data associated with them.
       
   840 	 * 
       
   841 	 * All types EXCEPT for ERename, EVolumeName and EDriveName have the following data 
       
   842 	 * and are aligned in the buffer like so:
       
   843 	 * Word1   : NotificationSize (2 bytes) , PathSize (2 bytes)
       
   844 	 * Word2   : NotificationType (Lower 2 bytes)
       
   845 	 * Word(s) : Path (TText8) , [Any sub-class members]
       
   846 	 * 
       
   847 	 * Else for notification types ERename, EVolumeName and EDriveName the order is:
       
   848 	 * Word1   : NotificationSize (2 bytes) , PathSize (2 bytes)
       
   849 	 * Word2   : NewNameSize (2 bytes) , NotificationType (2 bytes)
       
   850 	 * Word(s) : Path (TText8) , NewName (TText8)
       
   851 	 * 
       
   852 	 * Overflow notification type doesn't have a name, so its namesize is 0
       
   853 	 * and there will be no Word3.
       
   854 	 */	
       
   855 	
       
   856 	__PRINT(_L("CFsNotifyRequest::NotifyChange()"));
       
   857 
       
   858 	TInt notificationSize = FsNotificationHelper::NotificationSize(*aRequest,aNotificationType,aName);
       
   859 	
       
   860 	iClientSyncLock.Wait();
       
   861 	iTailSemaphore.Wait();
       
   862 	
       
   863 	TInt tail = iServerTail;
       
   864 	
       
   865 	//Validation
       
   866 	TBool overflow = ValidateNotification(notificationSize, tail);
       
   867 		
       
   868 	//Now that we know there is enough space in the buffer we can write 
       
   869 	//the standard attributes that all notifications have.
       
   870 
       
   871 	//We can store the size of the notification 
       
   872 	//and the size of the name in the same word.
       
   873 	
       
   874 	TUint16 nameLen = 0;	//Overflow has no name
       
   875 	TInt notifSize = KNotificationHeaderSize;
       
   876 	if(!overflow)
       
   877 		{
       
   878 		nameLen = (TUint16)aName.Size();
       
   879 		notifSize = notificationSize;
       
   880 		}
       
   881 	else 
       
   882 		{
       
   883 		aNotificationType = TFsNotification::EOverflow;
       
   884 		}	
       
   885 
       
   886 	iServerTail = tail + notifSize;
       
   887 	iTailSemaphore.Signal();
       
   888 	
       
   889 	TInt writeOffset = 0;	//Where to write in the block
       
   890 	
       
   891 	//Store notification Size and NameSize (Word1)
       
   892 	TUint sizeNameLen = (notifSize << 16) | nameLen;	
       
   893 	memcpy((TText8*)aBlock.Data()+writeOffset,&sizeNameLen,sizeof(TUint));
       
   894 	writeOffset+=sizeof(TUint);
       
   895 
       
   896 	TPtrC newName;
       
   897 	
       
   898 	if (aNotificationType == TFsNotification::ERename ||
       
   899 		aNotificationType == TFsNotification::EVolumeName ||
       
   900 		aNotificationType == TFsNotification::EDriveName)
       
   901 		{
       
   902 		FsNotificationHelper::NewPathName(*aRequest,newName);
       
   903 		//Store NewNameSize and notification Type (Word2)
       
   904 		TUint typeNewNameLen = ((TUint16)newName.Size() << 16) | (TUint16)aNotificationType;
       
   905 		memcpy((TText8*)aBlock.Data()+writeOffset,&typeNewNameLen,sizeof(TUint));
       
   906 		}
       
   907 	else
       
   908 		{
       
   909 		//Store notification Type (Word2)
       
   910 		memcpy((TText8*)aBlock.Data()+writeOffset,&aNotificationType,sizeof(TUint));
       
   911 		}
       
   912 	writeOffset+=sizeof(TUint);
       
   913 	
       
   914 	CFileShare* share = NULL;
       
   915     CFileCB* file = NULL;
       
   916     if(aRequest) //Don't always have a request such as when called from localdrives.
       
   917         {
       
   918         GetFileFromScratch(aRequest, share, file);
       
   919         }
       
   920     
       
   921     //
       
   922     //Store UID
       
   923     /*
       
   924 	TUid uid;
       
   925 	uid.iUid = KErrUnknown;
       
   926 	if(aRequest && aRequest->Operation()->iFunction == EFsFileWriteDirty)
       
   927 	    {
       
   928 	    uid = aRequest->iUID;
       
   929 	    }
       
   930 	else if(aRequest)
       
   931 	    {
       
   932 	    uid = aRequest->Message().Identity();
       
   933 	    }
       
   934 	memcpy((TText8*)aBlock.Data()+writeOffset,&uid.iUid,sizeof(TUint32));
       
   935 	writeOffset+=sizeof(TUint32);
       
   936 	*/
       
   937 	
       
   938 	if(!overflow)
       
   939 		{
       
   940 		//Store Name (Word3)
       
   941 		memcpy((TText8*)aBlock.Data()+writeOffset,aName.Ptr(),aName.Size());
       
   942 		writeOffset += Align4(aName.Size());
       
   943 		
       
   944 
       
   945 		switch (aNotificationType)
       
   946 			{
       
   947 			case TFsNotification::EFileChange:
       
   948 				{
       
   949 				TInt64 size = 0;
       
   950 				size = file->CachedSize64();
       
   951 				memcpy((TText8*)aBlock.Data()+writeOffset,&size,sizeof(TInt64));
       
   952 				writeOffset += sizeof(TInt64);
       
   953 				break;
       
   954 				}
       
   955 			case TFsNotification::ERename:
       
   956 			case TFsNotification::EVolumeName:
       
   957 			case TFsNotification::EDriveName:
       
   958 				{
       
   959 				//Store NewName
       
   960 				memcpy((TText8*)aBlock.Data()+writeOffset,newName.Ptr(),newName.Size());
       
   961 				writeOffset += Align4(newName.Size());
       
   962 				break;
       
   963 				}
       
   964 			case TFsNotification::EAttribute:
       
   965 				{
       
   966 				TUint set=0;
       
   967 				TUint clear=0;
       
   968 				FsNotificationHelper::Attributes(*aRequest,set,clear);
       
   969 				TUint64 att = MAKE_TUINT64(set,clear);
       
   970 				memcpy((TText8*)aBlock.Data()+writeOffset,&att,sizeof(TUint64));
       
   971 				writeOffset += sizeof(TUint64);
       
   972 				break;
       
   973 				}
       
   974 			default:
       
   975 				{
       
   976 				break;
       
   977 				}
       
   978 			}
       
   979 		}
       
   980 	
       
   981 	//Write to client buffer
       
   982 	TInt r = SynchroniseBuffer(aBlock,tail,notifSize);
       
   983 	
       
   984 	//Signal the iClientSyncLock. 
       
   985 	//When all locks on this are signaled then CompleteClientRequest can be called.
       
   986 	//This signal moves when we have a cache system
       
   987 	iClientSyncLock.Signal();
       
   988 	
       
   989 	//We need to complete if this was the first 
       
   990 	//write to the client's buffer
       
   991 	if(ClientMsgHandle()!=0 && r==KErrNone)
       
   992 		{
       
   993 		__PRINT4(_L("CFsNotifyRequest::NotifyChange iClientHead(%d) iClientTail(%d) iServerTail(%d) iClientBufferSize(%d)"),iClientHead,iClientTail,iServerTail,iClientBufferSize);
       
   994 		CompleteClientRequest(KErrNone);
       
   995 		}
       
   996 	else if(!overflow)
       
   997 		{
       
   998 		SetActive(CFsNotifyRequest::EOutstanding);
       
   999 		}
       
  1000 	else
       
  1001 		{
       
  1002 		SetActive(CFsNotifyRequest::EOutstandingOverflow);
       
  1003 		}
       
  1004 	
       
  1005 	if(r!= KErrNone)
       
  1006 		{
       
  1007 		//RDebug::Print(_L("sf_notifier.cpp line %d function = %d, r = %d"),__LINE__, aRequest->FsFunction(),r);
       
  1008 		//RDebug::Print(_L("iServerTail=%d, tail=%d, iClientBufferSize=%d, overflow=%d"),iServerTail,tail,iClientBufferSize,overflow);
       
  1009 		SetActive(CFsNotifyRequest::EInactive);
       
  1010 		}
       
  1011 	return r;
       
  1012 	}
       
  1013 
       
  1014 #ifdef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
       
  1015 
       
  1016 //A change has occurred in f32 represented by this
       
  1017 //request object. Work out which CfsNotify’s are interested
       
  1018 // (if any) and call CfsNotifyRequest::NotifyChange.
       
  1019 void FsNotificationManager::HandleChange(CFsClientMessageRequest* aRequest,const TDesC& aOperationName, TFsNotification::TFsNotificationType aType)
       
  1020 	{
       
  1021 	__PRINT2(_L("FsNotificationManager::HandleChange() aRequest=0x%x, aType=%d"),&aRequest,aType);
       
  1022 
       
  1023 	Lock(); //ToDo: Read Lock (Read/Write Lock)	
       
  1024 	if(Count())
       
  1025 		{
       
  1026 		//Only search while there are filters of this type set up.
       
  1027 		TInt index = FsNotificationHelper::TypeToIndex(aType);
       
  1028 		TInt& filterCount = FsNotificationManager::FilterRegister(index);
       
  1029 		TInt seenFilter = filterCount; //Number of requests set up for this type
       
  1030 		
       
  1031 		//Iterate CFsNotifyRequests
       
  1032 		TInt count = iNotifyRequests->Count();
       
  1033 		
       
  1034 		if(aType == TFsNotification::EMediaChange)
       
  1035 			seenFilter = count;
       
  1036 		
       
  1037 		//If there aren't any requests then breakout
       
  1038 		if(count == 0)
       
  1039 			{
       
  1040 			Unlock();
       
  1041 			return;
       
  1042 			}
       
  1043 		
       
  1044 		TInt driveNum = FsNotificationHelper::DriveNumber(aOperationName); 
       
  1045 
       
  1046 		//For every notification request.
       
  1047 		for(TInt i=0; i<count && seenFilter; ++i)
       
  1048 			{
       
  1049 			CFsNotifyRequest* notifyRequest = (CFsNotifyRequest*)(*iNotifyRequests)[i];
       
  1050 			CFsNotifyRequest::TNotifyRequestStatus status = notifyRequest->ActiveStatus();
       
  1051 			if(! (status==CFsNotifyRequest::EActive || 
       
  1052 				  status==CFsNotifyRequest::EOutstanding))
       
  1053 				{
       
  1054 				//Not active; check next notification request
       
  1055 				continue;
       
  1056 				}
       
  1057 			
       
  1058 			//Check whether we are interested in this change.
       
  1059 			//Get the filters associated with this operation on this drive
       
  1060 			TFsNotificationTypeArray* filterList = notifyRequest->FilterTypeList(driveNum,index);
       
  1061 			DoHandleChange(filterList,seenFilter,aRequest,notifyRequest,aOperationName,aType);
       
  1062 
       
  1063 			if(aType==TFsNotification::EMediaChange)
       
  1064 				continue; //next request
       
  1065 			
       
  1066 			//If there are still filters to check
       
  1067 			if(seenFilter)
       
  1068 				{
       
  1069 				//Check changes that are not tied to a particular drive
       
  1070 				filterList = notifyRequest->FilterTypeList(KErrNotFound,index);
       
  1071 				DoHandleChange(filterList,seenFilter,aRequest,notifyRequest,aOperationName,aType);
       
  1072 				}
       
  1073 			}
       
  1074 		}
       
  1075 	Unlock();
       
  1076 	}
       
  1077 
       
  1078 //A change has occurred in f32 represented by this
       
  1079 //request object. Work out which CfsNotify’s are interested
       
  1080 // (if any) and call CfsNotifyRequest::NotifyChange.
       
  1081 void FsNotificationManager::HandleChange(CFsClientMessageRequest& aRequest, TFsNotification::TFsNotificationType aType)
       
  1082 	{
       
  1083 	__PRINT(_L("FsNotificationManager::HandleChange"));
       
  1084 	TFileName currentOperationsName;
       
  1085 	FsNotificationHelper::PathName(aRequest, currentOperationsName);
       
  1086 	if(currentOperationsName.Length())
       
  1087 		HandleChange(&aRequest,currentOperationsName,aType);
       
  1088 	}
       
  1089 
       
  1090 //A change has occurred in f32 represented by this
       
  1091 //request object. Work out which CfsNotify’s are interested
       
  1092 // (if any) and call CfsNotifyRequest::NotifyChange.
       
  1093 void FsNotificationManager::HandleChange(CFsClientMessageRequest& aRequest)
       
  1094 	{
       
  1095 	if(Count() && aRequest.Message().Handle() != KLocalMessageHandle)
       
  1096 		{
       
  1097 		__PRINT(_L("FsNotificationManager::HandleChange"));
       
  1098 		TFsNotification::TFsNotificationType operationNotificationType;
       
  1099 		FsNotificationHelper::NotificationType(aRequest.FsFunction(), operationNotificationType);
       
  1100 		HandleChange(aRequest,operationNotificationType);
       
  1101 		}
       
  1102 	}
       
  1103 
       
  1104 
       
  1105 ////
       
  1106 #else
       
  1107 ////
       
  1108 
       
  1109 void FsNotificationManager::HandleChange(CFsClientMessageRequest* ,const TDesC&, TFsNotification::TFsNotificationType)
       
  1110 	{
       
  1111 	return;
       
  1112 	}
       
  1113 
       
  1114 void FsNotificationManager::HandleChange(CFsClientMessageRequest& , TFsNotification::TFsNotificationType)
       
  1115 	{
       
  1116 	return;
       
  1117 	}
       
  1118 
       
  1119 void FsNotificationManager::HandleChange(CFsClientMessageRequest&)
       
  1120 	{
       
  1121 	return;
       
  1122 	}
       
  1123 
       
  1124 #endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
       
  1125 
       
  1126 //Called from FsNotificationManager::DoHandleChange
       
  1127 FsNotificationManager::TFsNotificationFilterMatch FsNotificationManager::DoMatchFilter(CFsClientMessageRequest* aRequest, const TDesC& aOperationName,CFsNotificationPathFilter& aFilter)
       
  1128     {
       
  1129     TFsNotificationFilterMatch filterMatch = EDifferent;
       
  1130     TParsePtrC parseOp(aOperationName);
       
  1131     TPtrC pathOpDes = parseOp.DriveAndPath();
       
  1132     TPtrC nameOpDes = parseOp.NameAndExt();
       
  1133     TInt pathLength = aFilter.iPath->Des().Length();
       
  1134     TInt nameLength = aFilter.iFilename->Des().Length();
       
  1135     TInt paths = -1;
       
  1136     TInt names = -1;
       
  1137     if(pathLength != 0)
       
  1138         {
       
  1139         paths = pathOpDes.MatchF(aFilter.iPath->Des());
       
  1140         }
       
  1141     else //if no path filter was set up
       
  1142         // then we need to ensure we don't notify on data-caged areas which we shouldn't
       
  1143         {
       
  1144         TInt r = PathCheck(aRequest,aOperationName.Mid(2),&KCapFsSysFileTemp,&KCapFsPriFileTemp,&KCapFsROFileTemp, __PLATSEC_DIAGNOSTIC_STRING("FsNotificationManager::DoHandleChange"));
       
  1145         if(r != KErrNone)
       
  1146             return EContinue; //next filter
       
  1147         }
       
  1148     
       
  1149     if(nameLength != 0)
       
  1150         {
       
  1151         names = nameOpDes.MatchF(aFilter.iFilename->Des());  
       
  1152         }
       
  1153     //Check: Path & Names Match
       
  1154     if((paths == 0 || pathLength==0) &&                             //  paths match && 
       
  1155         (names >= 0 || (nameLength==0 && nameOpDes.Length()==0))) // names match OR there are no names (i.e. operation is a dir and no filename filter)
       
  1156         {
       
  1157          filterMatch = EMatch;
       
  1158         }
       
  1159     return filterMatch;
       
  1160     }
       
  1161 
       
  1162 // This is called on a per drive basis.
       
  1163 void FsNotificationManager::DoHandleChange(TFsNotificationTypeArray* aFilterTypeArray,TInt& aSeenFilter, CFsClientMessageRequest* aRequest, CFsNotifyRequest* aNotifyRequest, const TDesC& aOperationName, TFsNotification::TFsNotificationType& aType)
       
  1164 	{		
       
  1165 	__PRINT(_L("FsNotificationManager::DoHandleChange()"));
       
  1166 	
       
  1167 	if(!aFilterTypeArray)
       
  1168 		return;
       
  1169 	
       
  1170 	TInt numFilters = aFilterTypeArray->Count();
       
  1171 	
       
  1172 	if(aType == TFsNotification::EMediaChange)
       
  1173 		numFilters = 1; //Only need to notify once per drive.
       
  1174 		
       
  1175 	//For every filter in this request
       
  1176 	for(TInt j = 0; j < numFilters;++j)
       
  1177 		{
       
  1178 		//Is the correct notification type
       
  1179 		aSeenFilter--;
       
  1180 		
       
  1181 		TBool filterMatch = EDifferent;
       
  1182 		if(aType != TFsNotification::EMediaChange)
       
  1183 			{
       
  1184 			CFsNotificationPathFilter& filter = *(((*aFilterTypeArray)[j]).iPathFilter);
       
  1185 			__PRINT2(_L("FsNotificationManager::DoHandleChange() operationName=%S, filterName=%S"),&aOperationName,filter.iPath);
       
  1186 			
       
  1187 			filterMatch = DoMatchFilter(aRequest,aOperationName,filter);
       
  1188 			if(filterMatch == FsNotificationManager::EContinue)
       
  1189 			    continue; //triggers for data cages
       
  1190 			
       
  1191 			//We need to check for changes coming in to a directory when its rename
       
  1192 			if(aType == TFsNotification::ERename && filterMatch==FsNotificationManager::EDifferent)  
       
  1193                 {
       
  1194                 TPtrC aDestinationNamePtrC;
       
  1195                 FsNotificationHelper::NewPathName(*aRequest,aDestinationNamePtrC);
       
  1196                 __PRINT2(_L("FsNotificationManager::DoHandleChange() destinationName=%S, filterName=%S"),&aDestinationNamePtrC,filter.iPath);
       
  1197                 filterMatch = DoMatchFilter(aRequest,aDestinationNamePtrC,filter);
       
  1198                 }
       
  1199 			}
       
  1200 
       
  1201 		if(filterMatch || (aType == TFsNotification::EMediaChange))//Match or MediaChange (report regardless of filters)
       
  1202 			{
       
  1203 			//Matching - Handle change
       
  1204 			
       
  1205 			//Get a CFsNotificationBlock to use 
       
  1206 			//So that we can do IPC from a single place.
       
  1207 			CFsNotificationBlock* block = iPool->Allocate();
       
  1208 				
       
  1209 			TInt r = aNotifyRequest->NotifyChange(aRequest,aOperationName,aType,*block);
       
  1210 				
       
  1211 			//Free block
       
  1212 			iPool->Free(block);
       
  1213 				
       
  1214 			if(r != KErrNone)
       
  1215 				{
       
  1216 				//Something went wrong writing to the client's buffer
       
  1217 				aNotifyRequest->SetActive(CFsNotifyRequest::EInactive);
       
  1218 				if(aNotifyRequest->ClientMsgHandle()!=0)
       
  1219 					aNotifyRequest->CompleteClientRequest(r,EFalse);
       
  1220 				break; //Go to outer for (i.e. next request in HandleChange)
       
  1221 				}
       
  1222 			}	
       
  1223 		continue; //next filter
       
  1224 		}
       
  1225 	}