os/kernelhwsrv/userlibandfileserver/fileserver/sfile/sf_notifier.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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     if (aServerTail == iClientHead)
   754         {
   755         // Buffer is empty when Client Tail = Client Head
   756         if (iClientHead != iClientTail)
   757         	{
   758 			overflow = ETrue;
   759             return overflow;            
   760 			}
   761         }
   762 
   763 	//Work out remaining size taking account of whether the end position is
   764 	//before or after the overflow position.
   765 	TInt remainingSize = (iClientHead > aServerTail)
   766 			? iClientHead - aServerTail 
   767 			: iClientBufferSize - (aServerTail - iClientHead);
   768 
   769     TInt reservedSize = aNotificationSize;
   770     // + Save additional space for OVERFLOW
   771     reservedSize += KNotificationHeaderSize;
   772 
   773 	//
   774     // Have we wrapped around already?
   775     //
   776     if (iClientHead > aServerTail)
   777         {
   778 		// Yes,
   779 		// Buffer looks something like this:
   780 		//
   781         //            |CH             
   782         // [5678------1234]
   783         //     |ST		
   784 
   785 		//
   786 		//  Check if we can insert in the middle section:
   787 		//
   788 		if (remainingSize < reservedSize)
   789 			{
   790 			overflow = ETrue;
   791 			}	
   792 		//else:
   793 		// 	{
   794 		// 	We add new notification to middle 
   795         //	[5678***---1234]
   796         // 	}
   797 		//
   798 		return overflow;
   799         }
   800 
   801 
   802 	//
   803     // We have not wrapped around yet..
   804     //
   805     // Buffer looks something like this:
   806     //
   807     //    |CH      
   808     // [--123456789--]
   809     //            |ST
   810     //
   811 
   812 
   813 	//
   814     // Check up-front whether its possible for overflow to go at the beginning.
   815     // If there is not enough space at the start for overflow then we need to
   816     // check that's there's space for overflow at the end and must not rollover.
   817     //
   818     TBool canRollOver = ETrue;
   819     
   820     if (iClientHead < KNotificationHeaderSize)
   821         {
   822 		//
   823         //  |CH      
   824         // [123456789----]
   825         //          |ST
   826         //
   827         // No space for overflow at the beginning of buffer.
   828         //
   829         canRollOver = EFalse; 
   830         }
   831 
   832 	//
   833     // IF: Cannot rollover
   834     //
   835     if (!canRollOver)
   836         {
   837         //IF (notification + overflow) does not fit at the end overflow now.
   838         if ((iClientBufferSize - aServerTail) < reservedSize)
   839             {
   840             overflow = ETrue;
   841             }        
   842         //Else
   843         //	{
   844 		//	Add notification (**) to end [---12345678**---]
   845 		//	}
   846 
   847         }
   848     else 
   849 	// Can rollover  
   850 	// - need to check that notification fits at the end
   851 	//   or that notification+overflow fits at the beginning.
   852         {
   853         // If not enough space at end, rollover
   854         if ((iClientBufferSize - aServerTail) < aNotificationSize)
   855             {
   856 			//
   857 			// Add notification to start and fill end with Filler char 
   858             // [----0123456789#]
   859             //
   860             
   861             // IF we are not at the very end of the buffer,
   862 			// insert a KNotificationBufferFiller at iServerTail.
   863 			// When the client reads this, it sets iHead to 0 and reads from there.
   864 			if(iServerTail != iClientBufferSize)
   865 				{
   866 				//If there is space it will always be at least 1 word big
   867 				TPtrC8 fillerDes((TText8*) &KNotificationBufferFiller, sizeof(TUint));
   868 				iBufferMsg.Write(KMsgPtr0, fillerDes, aServerTail);
   869 				}
   870 
   871             // Now that we have rolled over we need to check whether there is
   872             // space at the beginning for notification + overflow
   873 			// We already know that overflow fits.
   874             if (reservedSize > iClientHead)
   875                 {
   876                 //  [ov--0123456789-]
   877                 overflow = ETrue;
   878                 }
   879 			//
   880 			// Add notification/overflow to the beginning
   881 			//  	[**--0123456789(#)]
   882 			//
   883 			aServerTail = 0;
   884 			}
   885 		//
   886 		// else - notification fits at the end so there is nothing to do here.
   887 		//
   888 		//
   889         }
   890     //
   891     //End Validation
   892     //
   893     return overflow;
   894     }
   895 
   896 // Called from FsNotificationManager::HandleChange().
   897 // Sends notifications into the client's buffer.
   898 // If there is a iClientMsg then this is the first time this
   899 // has been called since the client called RequestNotifications.
   900 // In this situation we complete the client request.
   901 TInt CFsNotifyRequest::NotifyChange(CFsClientMessageRequest* aRequest,const TDesC& aName, TFsNotification::TFsNotificationType aNotificationType, CFsNotificationBlock& aBlock)
   902 	{
   903 	/*
   904 	 * Different notification types have different data associated with them.
   905 	 * 
   906 	 * All types EXCEPT for ERename, EVolumeName and EDriveName have the following data 
   907 	 * and are aligned in the buffer like so:
   908 	 * Word1   : NotificationSize (2 bytes) , PathSize (2 bytes)
   909 	 * Word2   : NotificationType (Lower 2 bytes)
   910 	 * Word(s) : Path (TText8) , [Any sub-class members]
   911 	 * 
   912 	 * Else for notification types ERename, EVolumeName and EDriveName the order is:
   913 	 * Word1   : NotificationSize (2 bytes) , PathSize (2 bytes)
   914 	 * Word2   : NewNameSize (2 bytes) , NotificationType (2 bytes)
   915 	 * Word(s) : Path (TText8) , NewName (TText8)
   916 	 * 
   917 	 * Overflow notification type doesn't have a name, so its namesize is 0
   918 	 * and there will be no Word3.
   919 	 */	
   920 	
   921 	__PRINT(_L("CFsNotifyRequest::NotifyChange()"));
   922 
   923 	TInt notificationSize = FsNotificationHelper::NotificationSize(*aRequest,aNotificationType,aName);
   924 	
   925 	iClientSyncLock.Wait();
   926 	iTailSemaphore.Wait();
   927 	
   928 	TInt tail = iServerTail;
   929 	
   930 	//Validation
   931 	TBool overflow = ValidateNotification(notificationSize, tail);
   932 		
   933 	//Now that we know there is enough space in the buffer we can write 
   934 	//the standard attributes that all notifications have.
   935 
   936 	//We can store the size of the notification 
   937 	//and the size of the name in the same word.
   938 	
   939 	TUint16 nameLen = 0;	//Overflow has no name
   940 	TInt notifSize = KNotificationHeaderSize;
   941 	if(!overflow)
   942 		{
   943 		nameLen = (TUint16)aName.Size();
   944 		notifSize = notificationSize;
   945 		}
   946 	else 
   947 		{
   948 		aNotificationType = TFsNotification::EOverflow;
   949 		}	
   950 
   951 	iServerTail = tail + notifSize;
   952 	iTailSemaphore.Signal();
   953 	
   954 	TInt writeOffset = 0;	//Where to write in the block
   955 	
   956 	//Store notification Size and NameSize (Word1)
   957 	TUint sizeNameLen = (notifSize << 16) | nameLen;	
   958 	memcpy((TText8*)aBlock.Data()+writeOffset,&sizeNameLen,sizeof(TUint));
   959 	writeOffset+=sizeof(TUint);
   960 
   961 	TPtrC newName;
   962 	
   963 	if (aNotificationType == TFsNotification::ERename ||
   964 		aNotificationType == TFsNotification::EVolumeName ||
   965 		aNotificationType == TFsNotification::EDriveName)
   966 		{
   967 		FsNotificationHelper::NewPathName(*aRequest,newName);
   968 		//Store NewNameSize and notification Type (Word2)
   969 		TUint typeNewNameLen = ((TUint16)newName.Size() << 16) | (TUint16)aNotificationType;
   970 		memcpy((TText8*)aBlock.Data()+writeOffset,&typeNewNameLen,sizeof(TUint));
   971 		}
   972 	else
   973 		{
   974 		//Store notification Type (Word2)
   975 		memcpy((TText8*)aBlock.Data()+writeOffset,&aNotificationType,sizeof(TUint));
   976 		}
   977 	writeOffset+=sizeof(TUint);
   978 	
   979 	CFileShare* share = NULL;
   980     CFileCB* file = NULL;
   981     if(aRequest) //Don't always have a request such as when called from localdrives.
   982         {
   983         GetFileFromScratch(aRequest, share, file);
   984         }
   985     
   986     //
   987     //Store UID
   988     /*
   989 	TUid uid;
   990 	uid.iUid = KErrUnknown;
   991 	if(aRequest && aRequest->Operation()->iFunction == EFsFileWriteDirty)
   992 	    {
   993 	    uid = aRequest->iUID;
   994 	    }
   995 	else if(aRequest)
   996 	    {
   997 	    uid = aRequest->Message().Identity();
   998 	    }
   999 	memcpy((TText8*)aBlock.Data()+writeOffset,&uid.iUid,sizeof(TUint32));
  1000 	writeOffset+=sizeof(TUint32);
  1001 	*/
  1002 	
  1003 	if(!overflow)
  1004 		{
  1005 		//Store Name (Word3)
  1006 		memcpy((TText8*)aBlock.Data()+writeOffset,aName.Ptr(),aName.Size());
  1007 		writeOffset += Align4(aName.Size());
  1008 		
  1009 
  1010 		switch (aNotificationType)
  1011 			{
  1012 			case TFsNotification::EFileChange:
  1013 				{
  1014 				TInt64 size = 0;
  1015 				size = file->CachedSize64();
  1016 				memcpy((TText8*)aBlock.Data()+writeOffset,&size,sizeof(TInt64));
  1017 				writeOffset += sizeof(TInt64);
  1018 				break;
  1019 				}
  1020 			case TFsNotification::ERename:
  1021 			case TFsNotification::EVolumeName:
  1022 			case TFsNotification::EDriveName:
  1023 				{
  1024 				//Store NewName
  1025 				memcpy((TText8*)aBlock.Data()+writeOffset,newName.Ptr(),newName.Size());
  1026 				writeOffset += Align4(newName.Size());
  1027 				break;
  1028 				}
  1029 			case TFsNotification::EAttribute:
  1030 				{
  1031 				TUint set=0;
  1032 				TUint clear=0;
  1033 				FsNotificationHelper::Attributes(*aRequest,set,clear);
  1034 				TUint64 att = MAKE_TUINT64(set,clear);
  1035 				memcpy((TText8*)aBlock.Data()+writeOffset,&att,sizeof(TUint64));
  1036 				writeOffset += sizeof(TUint64);
  1037 				break;
  1038 				}
  1039 			default:
  1040 				{
  1041 				break;
  1042 				}
  1043 			}
  1044 		}
  1045 	
  1046 	//Write to client buffer
  1047 	TInt r = SynchroniseBuffer(aBlock,tail,notifSize);
  1048 	
  1049 	//Signal the iClientSyncLock. 
  1050 	//When all locks on this are signaled then CompleteClientRequest can be called.
  1051 	//This signal moves when we have a cache system
  1052 	iClientSyncLock.Signal();
  1053 	
  1054 	//We need to complete if this was the first 
  1055 	//write to the client's buffer
  1056     if (r == KErrNone)
  1057         {
  1058 		//We need to complete if this was the first 
  1059 		//write to the client's buffer
  1060         if(ClientMsgHandle()!=0)
  1061             {
  1062 			//RDebug::Print(_L("CFsNotifyRequest::NotifyChange iClientHead(%d) iClientTail(%d) iServerTail(%d) iClientBufferSize(%d)"),iClientHead,iClientTail,iServerTail,iClientBufferSize);
  1063             __PRINT4(_L("CFsNotifyRequest::NotifyChange iClientHead(%d) iClientTail(%d) iServerTail(%d) iClientBufferSize(%d)"),iClientHead,iClientTail,iServerTail,iClientBufferSize);
  1064             CompleteClientRequest(KErrNone);
  1065             }
  1066         else if(!overflow)
  1067             {
  1068 		SetActive(CFsNotifyRequest::EOutstanding);
  1069             }
  1070         else //Overflow
  1071             {
  1072 		SetActive(CFsNotifyRequest::EOutstandingOverflow);
  1073             }
  1074         }
  1075 	else // r!=KErrNone
  1076 		{
  1077 		//RDebug::Print(_L("sf_notifier.cpp line %d function = %d, r = %d"),__LINE__, aRequest->FsFunction(),r);
  1078 		//RDebug::Print(_L("iServerTail=%d, tail=%d, iClientBufferSize=%d, overflow=%d"),iServerTail,tail,iClientBufferSize,overflow);
  1079 		}
  1080 	return r;
  1081 	}
  1082 
  1083 #ifdef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
  1084 
  1085 //A change has occurred in f32 represented by this
  1086 //request object. Work out which CfsNotify’s are interested
  1087 // (if any) and call CfsNotifyRequest::NotifyChange.
  1088 void FsNotificationManager::HandleChange(CFsClientMessageRequest* aRequest,const TDesC& aOperationName, TFsNotification::TFsNotificationType aType)
  1089 	{
  1090 	__PRINT2(_L("FsNotificationManager::HandleChange() aRequest=0x%x, aType=%d"),&aRequest,aType);
  1091 
  1092 	Lock(); //ToDo: Read Lock (Read/Write Lock)	
  1093 	if(Count())
  1094 		{
  1095 		//Only search while there are filters of this type set up.
  1096 		TInt index = FsNotificationHelper::TypeToIndex(aType);
  1097 		TInt& filterCount = FsNotificationManager::FilterRegister(index);
  1098 		TInt seenFilter = filterCount; //Number of requests set up for this type
  1099 		
  1100 		//Iterate CFsNotifyRequests
  1101 		TInt count = iNotifyRequests->Count();
  1102 		
  1103 		if(aType == TFsNotification::EMediaChange)
  1104 			seenFilter = count;
  1105 		
  1106 		//If there aren't any requests then breakout
  1107 		if(count == 0)
  1108 			{
  1109 			Unlock();
  1110 			return;
  1111 			}
  1112 		
  1113 		TInt driveNum = FsNotificationHelper::DriveNumber(aOperationName); 
  1114 
  1115 		//For every notification request.
  1116 		for(TInt i=0; i<count && seenFilter; ++i)
  1117 			{
  1118 			CFsNotifyRequest* notifyRequest = (CFsNotifyRequest*)(*iNotifyRequests)[i];
  1119 			CFsNotifyRequest::TNotifyRequestStatus status = notifyRequest->ActiveStatus();
  1120 			if(! (status==CFsNotifyRequest::EActive || 
  1121 				  status==CFsNotifyRequest::EOutstanding))
  1122 				{
  1123 				//Not active; check next notification request
  1124 				continue;
  1125 				}
  1126 			
  1127 			//Check whether we are interested in this change.
  1128 			//Get the filters associated with this operation on this drive
  1129 			TFsNotificationTypeArray* filterList = notifyRequest->FilterTypeList(driveNum,index);
  1130 			DoHandleChange(filterList,seenFilter,aRequest,notifyRequest,aOperationName,aType);
  1131 
  1132 			if(aType==TFsNotification::EMediaChange)
  1133 				continue; //next request
  1134 			
  1135 			//If there are still filters to check
  1136 			if(seenFilter)
  1137 				{
  1138 				//Check changes that are not tied to a particular drive
  1139 				filterList = notifyRequest->FilterTypeList(KErrNotFound,index);
  1140 				DoHandleChange(filterList,seenFilter,aRequest,notifyRequest,aOperationName,aType);
  1141 				}
  1142 			}
  1143 		}
  1144 	Unlock();
  1145 	}
  1146 
  1147 //A change has occurred in f32 represented by this
  1148 //request object. Work out which CfsNotify’s are interested
  1149 // (if any) and call CfsNotifyRequest::NotifyChange.
  1150 void FsNotificationManager::HandleChange(CFsClientMessageRequest& aRequest, TFsNotification::TFsNotificationType aType)
  1151 	{
  1152 	__PRINT(_L("FsNotificationManager::HandleChange"));
  1153 	TFileName currentOperationsName;
  1154 	FsNotificationHelper::PathName(aRequest, currentOperationsName);
  1155 	if(currentOperationsName.Length())
  1156 		HandleChange(&aRequest,currentOperationsName,aType);
  1157 	}
  1158 
  1159 //A change has occurred in f32 represented by this
  1160 //request object. Work out which CfsNotify’s are interested
  1161 // (if any) and call CfsNotifyRequest::NotifyChange.
  1162 void FsNotificationManager::HandleChange(CFsClientMessageRequest& aRequest)
  1163 	{
  1164 	if(Count() && aRequest.Message().Handle() != KLocalMessageHandle)
  1165 		{
  1166 		__PRINT(_L("FsNotificationManager::HandleChange"));
  1167 		TFsNotification::TFsNotificationType operationNotificationType;
  1168 		FsNotificationHelper::NotificationType(aRequest.FsFunction(), operationNotificationType);
  1169 		HandleChange(aRequest,operationNotificationType);
  1170 		}
  1171 	}
  1172 
  1173 
  1174 ////
  1175 #else
  1176 ////
  1177 
  1178 void FsNotificationManager::HandleChange(CFsClientMessageRequest* ,const TDesC&, TFsNotification::TFsNotificationType)
  1179 	{
  1180 	return;
  1181 	}
  1182 
  1183 void FsNotificationManager::HandleChange(CFsClientMessageRequest& , TFsNotification::TFsNotificationType)
  1184 	{
  1185 	return;
  1186 	}
  1187 
  1188 void FsNotificationManager::HandleChange(CFsClientMessageRequest&)
  1189 	{
  1190 	return;
  1191 	}
  1192 
  1193 #endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
  1194 
  1195 //Called from FsNotificationManager::DoHandleChange
  1196 FsNotificationManager::TFsNotificationFilterMatch FsNotificationManager::DoMatchFilter(CFsClientMessageRequest* aRequest, const TDesC& aOperationName,CFsNotificationPathFilter& aFilter)
  1197     {
  1198     TFsNotificationFilterMatch filterMatch = EDifferent;
  1199     TParsePtrC parseOp(aOperationName);
  1200     TPtrC pathOpDes = parseOp.DriveAndPath();
  1201     TPtrC nameOpDes = parseOp.NameAndExt();
  1202     TInt pathLength = aFilter.iPath->Des().Length();
  1203     TInt nameLength = aFilter.iFilename->Des().Length();
  1204     TInt paths = -1;
  1205     TInt names = -1;
  1206     if(pathLength != 0)
  1207         {
  1208         paths = pathOpDes.MatchF(aFilter.iPath->Des());
  1209         }
  1210     else //if no path filter was set up
  1211         // then we need to ensure we don't notify on data-caged areas which we shouldn't
  1212         {
  1213         TInt r = PathCheck(aRequest,aOperationName.Mid(2),&KCapFsSysFileTemp,&KCapFsPriFileTemp,&KCapFsROFileTemp, __PLATSEC_DIAGNOSTIC_STRING("FsNotificationManager::DoHandleChange"));
  1214         if(r != KErrNone)
  1215             return EContinue; //next filter
  1216         }
  1217     
  1218     if(nameLength != 0)
  1219         {
  1220         names = nameOpDes.MatchF(aFilter.iFilename->Des());  
  1221         }
  1222     //Check: Path & Names Match
  1223     if((paths == 0 || pathLength==0) &&                             //  paths match && 
  1224         (names >= 0 || (nameLength==0 && nameOpDes.Length()==0))) // names match OR there are no names (i.e. operation is a dir and no filename filter)
  1225         {
  1226          filterMatch = EMatch;
  1227         }
  1228     return filterMatch;
  1229     }
  1230 
  1231 // This is called on a per drive basis.
  1232 void FsNotificationManager::DoHandleChange(TFsNotificationTypeArray* aFilterTypeArray,TInt& aSeenFilter, CFsClientMessageRequest* aRequest, CFsNotifyRequest* aNotifyRequest, const TDesC& aOperationName, TFsNotification::TFsNotificationType& aType)
  1233 	{		
  1234 	__PRINT(_L("FsNotificationManager::DoHandleChange()"));
  1235 	
  1236 	if(!aFilterTypeArray)
  1237 		return;
  1238 	
  1239 	TInt numFilters = aFilterTypeArray->Count();
  1240 	
  1241 	if(aType == TFsNotification::EMediaChange)
  1242 		numFilters = 1; //Only need to notify once per drive.
  1243 		
  1244 	//For every filter in this request
  1245 	for(TInt j = 0; j < numFilters;++j)
  1246 		{
  1247 		//Is the correct notification type
  1248 		aSeenFilter--;
  1249 		
  1250 		TBool filterMatch = EDifferent;
  1251 		if(aType != TFsNotification::EMediaChange)
  1252 			{
  1253 			CFsNotificationPathFilter& filter = *(((*aFilterTypeArray)[j]).iPathFilter);
  1254 			__PRINT2(_L("FsNotificationManager::DoHandleChange() operationName=%S, filterName=%S"),&aOperationName,filter.iPath);
  1255 			
  1256 			filterMatch = DoMatchFilter(aRequest,aOperationName,filter);
  1257 			if(filterMatch == FsNotificationManager::EContinue)
  1258 			    continue; //triggers for data cages
  1259 			
  1260 			//We need to check for changes coming in to a directory when its rename
  1261 			if(aType == TFsNotification::ERename && filterMatch==FsNotificationManager::EDifferent)  
  1262                 {
  1263                 TPtrC aDestinationNamePtrC;
  1264                 FsNotificationHelper::NewPathName(*aRequest,aDestinationNamePtrC);
  1265                 __PRINT2(_L("FsNotificationManager::DoHandleChange() destinationName=%S, filterName=%S"),&aDestinationNamePtrC,filter.iPath);
  1266                 filterMatch = DoMatchFilter(aRequest,aDestinationNamePtrC,filter);
  1267                 }
  1268 			}
  1269 
  1270 		if(filterMatch || (aType == TFsNotification::EMediaChange))//Match or MediaChange (report regardless of filters)
  1271 			{
  1272 			//Matching - Handle change
  1273 			
  1274 			//Get a CFsNotificationBlock to use 
  1275 			//So that we can do IPC from a single place.
  1276 			CFsNotificationBlock* block = iPool->Allocate();
  1277 				
  1278 			TInt r = aNotifyRequest->NotifyChange(aRequest,aOperationName,aType,*block);
  1279 				
  1280 			//Free block
  1281 			iPool->Free(block);
  1282 				
  1283 			if(r != KErrNone)
  1284 				{
  1285 				//Something went wrong writing to the client's buffer
  1286 				aNotifyRequest->SetActive(CFsNotifyRequest::EInactive);
  1287 				if(aNotifyRequest->ClientMsgHandle()!=0)
  1288 					aNotifyRequest->CompleteClientRequest(r,EFalse);
  1289 				break; //Go to outer for (i.e. next request in HandleChange)
  1290 				}
  1291 			}	
  1292 		continue; //next filter
  1293 		}
  1294 	}