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