userlibandfileserver/fileserver/sfile/sf_notifier.cpp
changeset 43 96e5fb8b040d
equal deleted inserted replaced
-1:000000000000 43:96e5fb8b040d
       
     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 	}