userlibandfileserver/fileserver/sfile/sf_notify.cpp
changeset 0 a41df078684a
child 19 4a8fed1c0ef6
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // f32\sfile\sf_notif.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "sf_std.h"
       
    19 
       
    20 
       
    21 
       
    22 TChangeQue FsNotify::iChangeQues[KMaxNotifyQues];
       
    23 TDiskSpaceQue FsNotify::iDiskSpaceQues[KMaxDiskQues];
       
    24 TDebugQue FsNotify::iDebugQue;
       
    25 TDismountNotifyQue FsNotify::iDismountNotifyQue;
       
    26 
       
    27 void CNotifyInfo::Initialise(TInfoType aType,TRequestStatus* aStatus,const RMessagePtr2& aMessage,CSessionFs* aSession)
       
    28 //
       
    29 //
       
    30 //
       
    31 	{
       
    32 	iType=aType;
       
    33 	iStatus=aStatus;
       
    34 	iMessage=aMessage;
       
    35 	iSession=aSession;
       
    36 	};
       
    37 
       
    38 CNotifyInfo::~CNotifyInfo()
       
    39 //
       
    40 //
       
    41 //
       
    42 	{
       
    43 	__ASSERT_DEBUG(!iLink.iNext,Fault(ENotifyInfoDestructor));
       
    44 	}
       
    45 
       
    46 void CNotifyInfo::Complete(TInt aError)
       
    47 //
       
    48 //
       
    49 //
       
    50 	{
       
    51 	__PRINT2(_L("CNotifyInfo::Complete 0x%x error=%d"),this,aError);
       
    52 	if (iType != EDismount || !iMessage.IsNull())	// Dismount notifiers may be completed but remain in the list
       
    53 		{											// until handled by the client or the session is closed.
       
    54 		iMessage.Complete(aError);
       
    55 		}
       
    56 	}
       
    57 
       
    58 
       
    59 void CStdChangeInfo::Initialise(TNotifyType aChangeType,TRequestStatus* aStatus,const RMessagePtr2& aMessage,CSessionFs* aSession)
       
    60 //
       
    61 //
       
    62 //
       
    63 	{
       
    64 	iChangeType=aChangeType;
       
    65 	CNotifyInfo::Initialise(EStdChange,aStatus,aMessage,aSession);
       
    66 	}
       
    67 
       
    68 TUint CStdChangeInfo::RequestNotifyType(CFsRequest* aRequest)
       
    69 //
       
    70 // return notification type for the request
       
    71 //
       
    72 	{
       
    73 	TUint notifyType=aRequest->Operation()->NotifyType();
       
    74 	if(aRequest->Operation()->Function()==EFsRename)
       
    75 		{
       
    76 		__ASSERT_DEBUG(notifyType==(ENotifyDir|ENotifyFile|ENotifyEntry),Fault(EStdChangeRequestType));
       
    77 		if(aRequest->Src().NamePresent())
       
    78 			notifyType=ENotifyFile|ENotifyEntry;
       
    79 		else
       
    80 			notifyType=ENotifyDir|ENotifyEntry;
       
    81 		}
       
    82 	return(notifyType);						
       
    83 	}
       
    84 
       
    85 TBool CStdChangeInfo::IsMatching(CFsRequest* aRequest)
       
    86 //
       
    87 // return ETrue if operation type of request matches that of change notification
       
    88 //
       
    89 	{
       
    90 	if((iChangeType&ENotifyAll) || (iChangeType&aRequest->Operation()->NotifyType()))
       
    91 		return(ETrue);
       
    92 	else
       
    93 		return(EFalse);
       
    94 	}
       
    95 
       
    96 void CExtChangeInfo::Initialise(TNotifyType aChangeType,TRequestStatus* aStatus,const RMessagePtr2& aMessage,CSessionFs* aSession,const TDesC& aName)
       
    97 //
       
    98 //
       
    99 //
       
   100 	{
       
   101 	__ASSERT_DEBUG(aName.Length()<=KMaxFileName-2,Fault(EExtChangeNameLength));
       
   102 	iName=aName;
       
   103 	iChangeType=aChangeType;
       
   104 	CNotifyInfo::Initialise(EExtChange,aStatus,aMessage,aSession);
       
   105 	}
       
   106 
       
   107 
       
   108 TBool CExtChangeInfo::IsMatching(CFsRequest* aRequest)
       
   109 //
       
   110 // return ETrue if operation notify type of request matches that of change notification
       
   111 // and paths match
       
   112 //
       
   113 	{
       
   114 	TInt function=aRequest->Operation()->Function();
       
   115 	//	if a rename occurred inform any requests if their path has been changed regardless of the notification type
       
   116 	if(function==EFsRename)				
       
   117 		{		
       
   118 		TBuf<KMaxFileName> renamePath=aRequest->Src().FullName().Mid(2);		
       
   119 		renamePath+=_L("*");
       
   120 		if (iName.MatchF(renamePath)!=KErrNotFound)	
       
   121 			return(ETrue);
       
   122 		}
       
   123 
       
   124 
       
   125 	//Special case where the dir the notifier is setup on has just been created
       
   126 	if(function==EFsMkDir)	
       
   127 		{		
       
   128 		TInt notDrive;
       
   129 		RFs::CharToDrive(aRequest->Src().Drive()[0],notDrive);	//can not fail as the drive letter has been parsed already
       
   130 		if(aRequest->Src().Path().MatchF(iName) == 0 && aRequest->DriveNumber() == notDrive)
       
   131 			return ETrue;
       
   132 		}
       
   133 	
       
   134 	//Special case where  the File the notifier is setup on has just been created by temp as the name is not known unti it has been created
       
   135 	if(function==EFsRename||function==EFsFileOpen||function==EFsFileCreate||function==EFsFileReplace)
       
   136 		{
       
   137 		TInt notDrive;
       
   138 		RFs::CharToDrive(aRequest->Src().Drive()[0],notDrive);	//can not fail as the drive letter has been parsed already
       
   139 		if(aRequest->Src().FullName().Mid(2).MatchF(iName) == 0 && aRequest->DriveNumber() == notDrive)
       
   140 			return ETrue;
       
   141 		}
       
   142 	
       
   143 	//For the case of a file created using EFsFileTemp we can probably ignore it for special cases as it 
       
   144 	//is created with a random name. Not specifically going to be being looked for
       
   145 
       
   146 	if((iChangeType&ENotifyAll) || (iChangeType&RequestNotifyType(aRequest)))
       
   147 		{
       
   148 		switch (function)
       
   149 			{	
       
   150 		//	Notify interested requests if a SetDriveName(), SetVolume() or RawDiskWrite() operation
       
   151 		//	occcurred.  By their nature, these operations have no distinct path.  All outstanding
       
   152 		//	requests monitoring the relevant TNotifyType are potentially interested in such operations	
       
   153 			case EFsFileWrite:
       
   154 			case EFsFileWriteDirty:
       
   155 			case EFsFileSet:
       
   156 			case EFsFileSetAtt:
       
   157 			case EFsFileSetModified:
       
   158 			case EFsFileSetSize:
       
   159 			{
       
   160 			TBuf<KMaxFileName> root=iName;
       
   161 			root+=_L("*");	
       
   162 			
       
   163 			// NB share may be NULL if file server has initiated a flush of the file cache
       
   164 			CFileShare* share;
       
   165 			CFileCB* fileCache;
       
   166 			GetFileFromScratch(aRequest, share, fileCache);
       
   167 			if (share && share->File().FileName().MatchF(root) != KErrNotFound)
       
   168 				return(ETrue);
       
   169 
       
   170 			}
       
   171 			break;
       
   172 			case EFsSetDriveName:
       
   173 			case EFsSetVolume:
       
   174 			case EFsRawDiskWrite:
       
   175 			case EFsLockDrive:
       
   176 			case EFsUnlockDrive:
       
   177 			case EFsReserveDriveSpace:
       
   178 				{
       
   179 				return(ETrue);				
       
   180 				}
       
   181 			
       
   182 			default:
       
   183 				{	
       
   184 				TBuf<KMaxFileName> root = iName;
       
   185 				root+=_L("*");	
       
   186 				
       
   187 				if(aRequest->Src().FullName().Mid(2).MatchF(root)!=KErrNotFound)
       
   188 					return(ETrue);	
       
   189 				else if(function==EFsRename||function==EFsReplace||function==EFsFileRename)
       
   190 					{
       
   191 					// - rename/replace causes the file/path to disappear
       
   192 					if(aRequest->Dest().FullName().Mid(2).MatchF(root)!=KErrNotFound)
       
   193 						{
       
   194 						return(ETrue);
       
   195 						}
       
   196 
       
   197 					// - rename/replace causes the file/path to arrive
       
   198 					root=aRequest->Dest().FullName().Mid(2);
       
   199 					root+=_L("*");
       
   200 
       
   201 					if (iName.MatchF(root)!=KErrNotFound)
       
   202 						{
       
   203 						return(ETrue);
       
   204 						}
       
   205 					}
       
   206 				}			
       
   207 			}
       
   208 		}
       
   209 	return(EFalse);
       
   210 	}
       
   211 
       
   212 
       
   213 void CDiskSpaceInfo::Initialise(TRequestStatus* aStatus,const RMessagePtr2& aMessage,CSessionFs* aSession,TInt64 aThreshold)
       
   214 //
       
   215 //
       
   216 //
       
   217 	{
       
   218 	__ASSERT_DEBUG(aThreshold>0,Fault(EDiskSpaceThreshold));
       
   219 	iThreshold=aThreshold;
       
   220 	CNotifyInfo::Initialise(EDiskSpace,aStatus,aMessage,aSession);
       
   221 	}
       
   222 
       
   223 TBool CDiskSpaceInfo::IsMatching(TInt64& aBefore,TInt64& aAfter)
       
   224 //
       
   225 // return ETrue if the threshold has been crossed
       
   226 //
       
   227 	{
       
   228 	if((aBefore>=iThreshold&&aAfter<iThreshold)||(aBefore<=iThreshold&&aAfter>iThreshold))
       
   229 		return(ETrue);
       
   230 	return(EFalse);
       
   231 	}
       
   232 
       
   233 void CDebugChangeInfo::Initialise(TUint aDebugType,TRequestStatus* aStatus,const RMessagePtr2& aMessage,CSessionFs* aSession)
       
   234 //
       
   235 //
       
   236 //
       
   237 	{
       
   238 	__ASSERT_DEBUG((aDebugType&KDebugNotifyMask)&&!(aDebugType&~KDebugNotifyMask),Fault(EDebugChangeType));
       
   239 	iDebugType=aDebugType;
       
   240 	CNotifyInfo::Initialise(EDebugChange,aStatus,aMessage,aSession);
       
   241 	}
       
   242 
       
   243 TBool CDebugChangeInfo::IsMatching(TUint aFunction)
       
   244 //
       
   245 // return ETrue if debug notification type matches aFunction
       
   246 //
       
   247 	{
       
   248 	if(iDebugType&aFunction)
       
   249 		return(ETrue);
       
   250 	return(EFalse);
       
   251 	}
       
   252 
       
   253 
       
   254 CDismountNotifyInfo::~CDismountNotifyInfo()
       
   255 	{
       
   256 	switch(iMode)
       
   257 		{
       
   258 		case EFsDismountNotifyClients:
       
   259 			break;
       
   260 		case EFsDismountRegisterClient:
       
   261 			__ASSERT_ALWAYS(TheDrives[iDriveNumber].DismountUnlock() >= 0, Fault(ENotifyDismountCancel));
       
   262 			break;
       
   263 		default:
       
   264 			break;
       
   265 		}
       
   266 	}
       
   267 
       
   268 void CDismountNotifyInfo::Initialise(TNotifyDismountMode aMode, TInt aDriveNumber, TRequestStatus* aStatus,const RMessagePtr2& aMessage,CSessionFs* aSession)
       
   269 	{
       
   270 	iMode = aMode;
       
   271 	iDriveNumber=aDriveNumber;
       
   272 	CNotifyInfo::Initialise(EDismount,aStatus,aMessage,aSession);
       
   273 
       
   274 	if (iMode == EFsDismountRegisterClient)
       
   275 		TheDrives[iDriveNumber].DismountLock();
       
   276 	}
       
   277 
       
   278 TBool CDismountNotifyInfo::IsMatching(TNotifyDismountMode aMode, TInt aDriveNumber, CSessionFs* aSession)
       
   279 	{
       
   280 	if((iDriveNumber == aDriveNumber) && (iMode == aMode) && (aSession == NULL || aSession == Session()))
       
   281 		return(ETrue);
       
   282 	return(EFalse);
       
   283 	}
       
   284 
       
   285 TBaseQue::TBaseQue()
       
   286 //
       
   287 //
       
   288 //
       
   289 	{
       
   290 	iHeader.SetOffset(_FOFF(CNotifyInfo,iLink));
       
   291 	TInt r=iQLock.CreateLocal();
       
   292 	__ASSERT_ALWAYS(r==KErrNone,Fault(EBaseQueConstruction));
       
   293 	}
       
   294 
       
   295 TBaseQue::~TBaseQue()
       
   296 //
       
   297 //
       
   298 //
       
   299 	{
       
   300 	iQLock.Close();
       
   301 	}
       
   302 
       
   303 void TBaseQue::DoAddNotify(CNotifyInfo* aInfo)
       
   304 //
       
   305 // Add notification
       
   306 // Que should be locked by calling function
       
   307 //
       
   308 	{
       
   309 	iHeader.AddLast(*aInfo);
       
   310 	}
       
   311 
       
   312 TBool TBaseQue::DoCancelSession(CSessionFs* aSession,TInt aCompletionCode, TRequestStatus* aStatus)
       
   313 //
       
   314 // Cancel notification(s) setup by aSession matching aStatus if set
       
   315 // Que should be locked by calling function
       
   316 //
       
   317 	{
       
   318 	TDblQueIter<CNotifyInfo> q(iHeader);
       
   319 	CNotifyInfo* info;
       
   320 	TBool isFound=EFalse;
       
   321 	while((info=q++)!=NULL)
       
   322 		{
       
   323 		if(info->Session()==aSession && (!aStatus || aStatus==info->Status()))
       
   324 			{
       
   325 			isFound=ETrue;
       
   326 			info->Complete(aCompletionCode);
       
   327 			info->iLink.Deque();
       
   328 			delete(info);
       
   329 			if(aStatus)
       
   330 				break;
       
   331 			}
       
   332 		}
       
   333 	return(isFound);
       
   334 	}
       
   335 
       
   336 void TBaseQue::DoCancelAll(TInt aCompletionCode)
       
   337 //
       
   338 // Cancel all notifications
       
   339 // Que should be locked by calling function
       
   340 //
       
   341 	{
       
   342 	TDblQueIter<CNotifyInfo> q(iHeader);
       
   343 	CNotifyInfo* info;
       
   344 	while((info=q++)!=NULL)
       
   345 		{
       
   346 		info->Complete(aCompletionCode);
       
   347 		info->iLink.Deque();
       
   348 		delete(info);
       
   349 		}
       
   350 	__ASSERT_DEBUG(iHeader.IsEmpty(),Fault(EBaseQueCancel));
       
   351 	}
       
   352 
       
   353 TBool TBaseQue::IsEmpty()
       
   354 //
       
   355 // Que should be locked by calling function
       
   356 //
       
   357 	{
       
   358 	return iHeader.IsEmpty();
       
   359 	}
       
   360 
       
   361 TBool TChangeQue::IsEmpty()
       
   362 //
       
   363 //
       
   364 //
       
   365 	{
       
   366 	iQLock.Wait();
       
   367 	TBool empty = TBaseQue::IsEmpty();
       
   368 	iQLock.Signal();
       
   369 	return(empty);
       
   370 	}
       
   371 	
       
   372 TInt TChangeQue::AddNotify(CNotifyInfo* aInfo)
       
   373 //
       
   374 //
       
   375 //
       
   376 	{
       
   377 	iQLock.Wait();
       
   378 	TBaseQue::DoAddNotify(aInfo);
       
   379 	iQLock.Signal();
       
   380 	return(KErrNone);
       
   381 	}
       
   382 
       
   383 TBool TChangeQue::CancelSession(CSessionFs* aSession,TInt aCompletionCode,TRequestStatus* aStatus)
       
   384 //
       
   385 //
       
   386 //
       
   387 	{
       
   388 	iQLock.Wait();
       
   389 	TBool isFound=TBaseQue::DoCancelSession(aSession,aCompletionCode,aStatus);
       
   390 	iQLock.Signal();
       
   391 	return(isFound);
       
   392 	}
       
   393 
       
   394 void TChangeQue::CancelAll(TInt aCompletionCode)
       
   395 //
       
   396 //
       
   397 //
       
   398 	{
       
   399 	iQLock.Wait();
       
   400 	TBaseQue::DoCancelAll(aCompletionCode);
       
   401 	iQLock.Signal();
       
   402 	}
       
   403 
       
   404 void TChangeQue::CheckChange(CFsRequest* aRequest)
       
   405 //
       
   406 // complete any notification in que that matches aRequest
       
   407 //
       
   408 	{
       
   409 	iQLock.Wait();
       
   410 	TDblQueIter<CNotifyInfo> q(iHeader);
       
   411 	CNotifyInfo* info;
       
   412 	while((info=q++)!=NULL)
       
   413 		{
       
   414 		__ASSERT_DEBUG(info->Type()==CNotifyInfo::EStdChange||info->Type()==CNotifyInfo::EExtChange,Fault(EChangeQueType));
       
   415 		TBool isMatching;
       
   416 		if(info->Type()==CNotifyInfo::EStdChange)
       
   417 			isMatching=((CStdChangeInfo*)info)->IsMatching(aRequest);
       
   418 		else
       
   419 			isMatching=((CExtChangeInfo*)info)->IsMatching(aRequest);
       
   420 		if(isMatching)
       
   421 			{
       
   422 			__PRINT1(_L("TChangeQue::CheckChange()-Matching info=0x%x"),info);
       
   423 			info->Complete(KErrNone);
       
   424 			info->iLink.Deque();
       
   425 			delete(info);
       
   426 			}
       
   427 		}
       
   428 	iQLock.Signal();
       
   429 	}
       
   430 
       
   431 TBool TDiskSpaceQue::IsEmpty()
       
   432 //
       
   433 //
       
   434 //
       
   435 	{
       
   436 	iQLock.Wait();
       
   437 	TBool empty = TBaseQue::IsEmpty();
       
   438 	iQLock.Signal();
       
   439 	return(empty);
       
   440 	}
       
   441 
       
   442 TInt TDiskSpaceQue::AddNotify(CNotifyInfo* aInfo)
       
   443 //
       
   444 //
       
   445 //
       
   446 	{
       
   447 	iQLock.Wait();
       
   448 	TInt r=KErrNone;
       
   449 	if(iHeader.IsEmpty())
       
   450 		{
       
   451 		r=GetFreeDiskSpace(iFreeDiskSpace);
       
   452 		iReservedDiskSpace = TheDrives[iDriveNumber].ReservedSpace();
       
   453 		}
       
   454 	if(r==KErrNone)
       
   455 		TBaseQue::DoAddNotify(aInfo);
       
   456 	iQLock.Signal();
       
   457 	return(r);
       
   458 	}
       
   459 
       
   460 TInt TDiskSpaceQue::CancelSession(CSessionFs* aSession,TInt aCompletionCode,TRequestStatus* aStatus)
       
   461 //
       
   462 //
       
   463 //
       
   464 	{
       
   465 	iQLock.Wait();
       
   466 	TBaseQue::DoCancelSession(aSession,aCompletionCode,aStatus);
       
   467 	iQLock.Signal();
       
   468 	return(KErrNone);
       
   469 	}
       
   470 
       
   471 void TDiskSpaceQue::CancelAll(TInt aCompletionCode)
       
   472 //
       
   473 //
       
   474 //
       
   475 	{
       
   476 	iQLock.Wait();
       
   477 	TBaseQue::DoCancelAll(aCompletionCode);
       
   478 	iQLock.Signal();
       
   479 	}
       
   480 
       
   481 
       
   482 void TDiskSpaceQue::CheckDiskSpace()
       
   483 //
       
   484 // Complete any disk space notification whose threshold has been crossed
       
   485 //
       
   486 	{
       
   487 	iQLock.Wait();
       
   488 	if(iHeader.IsEmpty())
       
   489 		{
       
   490 		iQLock.Signal();
       
   491 		return;
       
   492 		}
       
   493 	TInt64 freeSpace;
       
   494 	TInt r=GetFreeDiskSpace(freeSpace);
       
   495 	TInt64 reservedSpace(TheDrives[iDriveNumber].ReservedSpace());
       
   496 	if(r==KErrNone)
       
   497 		{
       
   498 		if((freeSpace==iFreeDiskSpace) && (reservedSpace==iReservedDiskSpace))
       
   499 			{
       
   500 			iQLock.Signal();
       
   501 			return;
       
   502 			}
       
   503 		TDblQueIter<CNotifyInfo> q(iHeader);
       
   504 		CNotifyInfo* info;
       
   505 		while((info=q++)!=NULL)
       
   506 			{
       
   507 			__ASSERT_DEBUG(info->Type()==CNotifyInfo::EDiskSpace,Fault(EDiskSpaceQueType1));
       
   508 
       
   509 			TInt64 newSessionFreeSpace(freeSpace);
       
   510 			TInt64 oldSessionFreeSpace(iFreeDiskSpace);
       
   511 			if(!info->Session()->ReservedAccess(iDriveNumber))
       
   512 				{
       
   513 				newSessionFreeSpace -= reservedSpace;
       
   514 				oldSessionFreeSpace -= iReservedDiskSpace;
       
   515 				}
       
   516 
       
   517 			if(((CDiskSpaceInfo*)info)->IsMatching(oldSessionFreeSpace,newSessionFreeSpace))
       
   518 				{
       
   519 				__PRINT1(_L("TDiskSpaceQue::CheckDiskSpace()-Matching info=0x%x"),info);
       
   520 				info->Complete(KErrNone);
       
   521 				info->iLink.Deque();
       
   522 				delete(info);
       
   523 				}
       
   524 			}
       
   525 		iFreeDiskSpace=freeSpace;
       
   526 		iReservedDiskSpace=reservedSpace;
       
   527 		}
       
   528 	else
       
   529 		TBaseQue::DoCancelAll(KErrNone);
       
   530 	iQLock.Signal();
       
   531 	}
       
   532 
       
   533 void TDiskSpaceQue::CheckDiskSpace(TInt64& aFreeDiskSpace)
       
   534 //
       
   535 //
       
   536 //
       
   537 	{
       
   538 	iQLock.Wait();
       
   539 	if(iHeader.IsEmpty())
       
   540 		{
       
   541 		iQLock.Signal();
       
   542 		return;
       
   543 		}
       
   544 
       
   545 	TInt64 reservedSpace(TheDrives[iDriveNumber].ReservedSpace());
       
   546 
       
   547 	if((aFreeDiskSpace==iFreeDiskSpace) && (reservedSpace==iReservedDiskSpace))
       
   548 		{
       
   549 		iQLock.Signal();
       
   550 		return;
       
   551 		}
       
   552 	TDblQueIter<CNotifyInfo> q(iHeader);
       
   553 	CNotifyInfo* info;
       
   554 	while((info=q++)!=NULL)
       
   555 		{
       
   556 		__ASSERT_DEBUG(info->Type()==CNotifyInfo::EDiskSpace,Fault(EDiskSpaceQueType2));
       
   557 
       
   558 		TInt64 newSessionFreeSpace(aFreeDiskSpace);
       
   559 		TInt64 oldSessionFreeSpace(iFreeDiskSpace);
       
   560 		if(!info->Session()->ReservedAccess(iDriveNumber))
       
   561 			{
       
   562 			newSessionFreeSpace -= reservedSpace;
       
   563 			oldSessionFreeSpace -= iReservedDiskSpace;
       
   564 			}
       
   565 
       
   566 		if(((CDiskSpaceInfo*)info)->IsMatching(oldSessionFreeSpace,newSessionFreeSpace))
       
   567 			{
       
   568 			__PRINT1(_L("TDiskSpaceQue::CheckDiskSpace()-Matching info=0x%x"),info);
       
   569 			info->Complete(KErrNone);
       
   570 			info->iLink.Deque();
       
   571 			delete(info);
       
   572 			}
       
   573 		}
       
   574 	iFreeDiskSpace=aFreeDiskSpace;
       
   575 	iReservedDiskSpace=reservedSpace;
       
   576 	iQLock.Signal();
       
   577 	}
       
   578 
       
   579 TInt TDiskSpaceQue::GetFreeDiskSpace(TInt64& aFreeDiskSpace)
       
   580 //
       
   581 // 
       
   582 //
       
   583 	{
       
   584 	__ASSERT_DEBUG(iDriveNumber>=EDriveA&&iDriveNumber<=EDriveZ,Fault(EDiskSpaceQueDrive));
       
   585 	__CHECK_DRIVETHREAD(iDriveNumber);
       
   586 	TInt r=TheDrives[iDriveNumber].FreeDiskSpace(aFreeDiskSpace);
       
   587 	return(r);
       
   588 	}
       
   589 
       
   590 TInt TDebugQue::AddNotify(CNotifyInfo* aInfo)
       
   591 //
       
   592 //
       
   593 //
       
   594 	{
       
   595 	iQLock.Wait();
       
   596 	TBaseQue::DoAddNotify(aInfo);
       
   597 	iQLock.Signal();
       
   598 	return(KErrNone);
       
   599 	}
       
   600 
       
   601 TInt TDebugQue::CancelSession(CSessionFs* aSession,TInt aCompletionCode,TRequestStatus* aStatus)
       
   602 //
       
   603 //
       
   604 //
       
   605 	{
       
   606 	iQLock.Wait();
       
   607 	TBool isFound=TBaseQue::DoCancelSession(aSession,aCompletionCode,aStatus);
       
   608 	iQLock.Signal();
       
   609 	return(isFound);
       
   610 	}
       
   611 
       
   612 void TDebugQue::CancelAll(TInt aCompletionCode)
       
   613 //
       
   614 //
       
   615 //
       
   616 	{
       
   617 	iQLock.Wait();
       
   618 	TBaseQue::DoCancelAll(aCompletionCode);
       
   619 	iQLock.Signal();
       
   620 	}
       
   621 
       
   622 void TDebugQue::CheckDebug(TUint aDebugChange)
       
   623 //
       
   624 // Complete any debug notification whose debug type matches aDebugChange
       
   625 //
       
   626 	{
       
   627 	iQLock.Wait();
       
   628 	TDblQueIter<CNotifyInfo> q(iHeader);
       
   629 	CNotifyInfo* info;
       
   630 	while((info=q++)!=NULL)
       
   631 		{
       
   632 		__ASSERT_DEBUG(info->Type()==CNotifyInfo::EDebugChange,Fault(EDebugQueType));
       
   633 		if(((CDebugChangeInfo*)info)->IsMatching(aDebugChange))
       
   634 			{
       
   635 			__PRINT1(_L("TDebugQue::CheckDebug()-Matching info=0x%x"),info);
       
   636 			info->Complete(KErrNone);
       
   637 			info->iLink.Deque();
       
   638 			delete(info);
       
   639 			}
       
   640 		}
       
   641 	iQLock.Signal();
       
   642 	}
       
   643 
       
   644 TInt TDismountNotifyQue::AddNotify(CNotifyInfo* aInfo)
       
   645 //
       
   646 //
       
   647 //
       
   648 	{
       
   649 	iQLock.Wait();
       
   650 	TBaseQue::DoAddNotify(aInfo);
       
   651 	iQLock.Signal();
       
   652 	return(KErrNone);
       
   653 	}
       
   654 
       
   655 TInt TDismountNotifyQue::CancelSession(CSessionFs* aSession,TInt aCompletionCode,TRequestStatus* aStatus)
       
   656 //
       
   657 //
       
   658 //
       
   659 	{
       
   660 	iQLock.Wait();
       
   661 	TBool isFound=TBaseQue::DoCancelSession(aSession,aCompletionCode,aStatus);
       
   662 	iQLock.Signal();
       
   663 	return(isFound);
       
   664 	}
       
   665 
       
   666 void TDismountNotifyQue::CancelAll(TInt aCompletionCode)
       
   667 //
       
   668 //
       
   669 //
       
   670 	{
       
   671 	iQLock.Wait();
       
   672 	TBaseQue::DoCancelAll(aCompletionCode);
       
   673 	iQLock.Signal();
       
   674 	}
       
   675 
       
   676 void TDismountNotifyQue::CheckDismount(TNotifyDismountMode aMode, TInt aDrive, TBool aRemove, TInt aError)
       
   677 //
       
   678 // Complete any dismount notifications on the specified drive.
       
   679 //
       
   680 	{
       
   681 	iQLock.Wait();
       
   682 	TDblQueIter<CNotifyInfo> q(iHeader);
       
   683 	CNotifyInfo* info;
       
   684 	while((info=q++)!=NULL)
       
   685 		{
       
   686 		__ASSERT_DEBUG(info->Type()==CNotifyInfo::EDismount,Fault(EBadDismountNotifyType));
       
   687 		if(((CDismountNotifyInfo*)info)->IsMatching(aMode, aDrive, NULL))
       
   688 			{
       
   689 			__PRINT1(_L("TDismountNotifyQue::CheckDismount()-Matching info=0x%x"),info);
       
   690 			info->Complete(aError);
       
   691 			if(aRemove)
       
   692 				{
       
   693 				info->iLink.Deque();
       
   694 				delete(info);
       
   695 				}
       
   696 			}
       
   697 		}
       
   698 
       
   699 	__ASSERT_ALWAYS(!aRemove || TheDrives[aDrive].DismountLocked() == 0, Fault(EDismountLocked));
       
   700 
       
   701 	iQLock.Signal();
       
   702 	}
       
   703 
       
   704 TBool TDismountNotifyQue::HandlePendingDismount(CSessionFs* aSession, TInt aDrive)
       
   705 //
       
   706 // Determine if the session has any outstanding dismount notifications on the specified drive.
       
   707 //
       
   708 	{
       
   709 	iQLock.Wait();
       
   710 	TDblQueIter<CNotifyInfo> q(iHeader);
       
   711 	CNotifyInfo* info;
       
   712 	while((info=q++)!=NULL)
       
   713 		{
       
   714 		__ASSERT_DEBUG(info->Type()==CNotifyInfo::EDismount,Fault(EBadDismountNotifyType));
       
   715 		if(((CDismountNotifyInfo*)info)->IsMatching(EFsDismountRegisterClient, aDrive, aSession))
       
   716 			{
       
   717 			__PRINT1(_L("TDismountNotifyQue::CheckDismount()-Pending info=0x%x"),info);
       
   718 			info->iLink.Deque();
       
   719 			delete(info);
       
   720 			iQLock.Signal();
       
   721 			return ETrue;
       
   722 			}
       
   723 		}
       
   724 	iQLock.Signal();
       
   725 	return EFalse;
       
   726 	}
       
   727 
       
   728 void FsNotify::Initialise()
       
   729 //
       
   730 //
       
   731 //
       
   732 	{
       
   733 	for(TInt i=0;i<KMaxDiskQues;++i)
       
   734 		{
       
   735 		iDiskSpaceQues[i].SetDriveNumber(i);
       
   736 		}
       
   737 	}
       
   738 
       
   739 TBool FsNotify::IsChangeQueEmpty(TInt aDrive)
       
   740 //
       
   741 //
       
   742 //
       
   743 	{
       
   744 	if((iChangeQues[ChangeIndex(aDrive)].IsEmpty()) && (iChangeQues[ChangeIndex(KDriveInvalid)].IsEmpty()))
       
   745 		return ETrue;
       
   746 
       
   747 	return EFalse;
       
   748 	}
       
   749 
       
   750 TInt FsNotify::AddChange(CNotifyInfo* aInfo,TInt aDrive)
       
   751 //
       
   752 //
       
   753 //
       
   754 	{
       
   755 	__ASSERT_DEBUG(aInfo->Type()==CNotifyInfo::EStdChange||aInfo->Type()==CNotifyInfo::EExtChange,Fault(EBadChangeNotifyType));
       
   756 	__PRINT2(_L("FsNotify::AddChange() drive=%d,info=0x%x"),aDrive,aInfo);
       
   757 	iChangeQues[ChangeIndex(aDrive)].AddNotify(aInfo);
       
   758 	return(KErrNone);
       
   759 	}
       
   760 
       
   761 TBool FsNotify::IsDiskSpaceQueEmpty(TInt aDrive)
       
   762 //
       
   763 //
       
   764 //
       
   765 	{
       
   766 	if(iDiskSpaceQues[aDrive].IsEmpty())
       
   767 		return ETrue;
       
   768 
       
   769 	return EFalse;
       
   770 	}
       
   771 
       
   772 TInt FsNotify::AddDiskSpace(CNotifyInfo* aInfo,TInt aDrive)
       
   773 //
       
   774 //
       
   775 //
       
   776 	{
       
   777 	__ASSERT_DEBUG(aInfo->Type()==CNotifyInfo::EDiskSpace,Fault(EBadDiskNotifyType));
       
   778 	__ASSERT_DEBUG((aDrive>=EDriveA && aDrive<=EDriveZ),Fault(EDiskBadIndex1));
       
   779 	__PRINT2(_L("FsNotify::AddDiskSpace() drive=%d,info=0x%x"),aDrive,aInfo);
       
   780 	return(iDiskSpaceQues[aDrive].AddNotify(aInfo));
       
   781 	}
       
   782 
       
   783 TInt FsNotify::AddDebug(CNotifyInfo* aDebugInfo)
       
   784 //
       
   785 //
       
   786 //
       
   787 	{
       
   788 	__ASSERT_DEBUG(aDebugInfo->Type()==CNotifyInfo::EDebugChange,Fault(EBadDebugNotifyType));
       
   789 	__PRINT1(_L("FsNotify::AddDebug() info=0x%x"),aDebugInfo);
       
   790 	iDebugQue.AddNotify(aDebugInfo);
       
   791 	return(KErrNone);
       
   792 	}
       
   793 
       
   794 TInt FsNotify::AddDismountNotify(CNotifyInfo* aDismountNotifyInfo)
       
   795 //
       
   796 //
       
   797 //
       
   798 	{
       
   799 	__ASSERT_DEBUG(aDismountNotifyInfo->Type()==CNotifyInfo::EDismount,Fault(EBadDismountNotifyType));
       
   800 	__PRINT1(_L("FsNotify::AddDismountNotify() info=0x%x"),aDismountNotifyInfo);
       
   801 	iDismountNotifyQue.AddNotify(aDismountNotifyInfo);
       
   802 	return(KErrNone);
       
   803 	}
       
   804 
       
   805 void FsNotify::HandleChange(CFsRequest* aRequest,TInt aDrive)
       
   806 //
       
   807 // Check whether any change notifications need to be completed due to aRequest on aDrive
       
   808 //
       
   809 	{
       
   810 	__PRINT2(_L("FsNotify::HandleChange() aRequest=0x%x, aDrive=%d"),aRequest,aDrive);
       
   811 	if(!aRequest->IsChangeNotify())
       
   812 		return;
       
   813 	iChangeQues[ChangeIndex(aDrive)].CheckChange(aRequest);
       
   814 	iChangeQues[ChangeIndex(KDriveInvalid)].CheckChange(aRequest);
       
   815 	}
       
   816 	
       
   817 
       
   818 void FsNotify::HandleDiskSpace(CFsRequest* aRequest,TInt aDrive)
       
   819 //
       
   820 // Check whether any disk space notifications need to be completed due to aRequest on aDrive
       
   821 //
       
   822 	{
       
   823 	__ASSERT_DEBUG((aDrive>=EDriveA && aDrive<=EDriveZ) || aDrive==KDriveInvalid,Fault(EDiskBadIndex2));
       
   824 	__PRINT2(_L("FsNotify::HandleDiskSpace() aRequest=0x%x, aDrive=%d"),aRequest,aDrive);
       
   825 	
       
   826 	if(!aRequest->Operation()->IsDiskSpaceNotify())
       
   827 		return;
       
   828 	TInt f = aRequest->Operation()->Function();
       
   829 	if ((f == EFsFileWrite || f == EFsFileWriteDirty) && !((CFsClientMessageRequest*)aRequest)->IsFreeChanged())
       
   830 		return;
       
   831 	if (FsThreadManager::IsDriveThread(aDrive,EFalse))	
       
   832 		iDiskSpaceQues[aDrive].CheckDiskSpace();
       
   833 	}
       
   834 
       
   835 void FsNotify::HandleDiskSpace(TInt aDrive, TInt64& aFreeSpace)
       
   836 //
       
   837 //
       
   838 //
       
   839 	{
       
   840 	__ASSERT_DEBUG((aDrive>=EDriveA && aDrive<=EDriveZ),Fault(EDiskBadIndex3));
       
   841 	__PRINT1(_L("FsNotify::HandleDiskSpace() aDrive=%d"),aDrive);
       
   842 	iDiskSpaceQues[aDrive].CheckDiskSpace(aFreeSpace);
       
   843 	}
       
   844 
       
   845 void FsNotify::HandleDebug(TUint aFunction)
       
   846 //
       
   847 // Check whether any debug notifications need to be completed due to aFunction
       
   848 //
       
   849 	{
       
   850 	__PRINT1(_L("FsNotify::HandleDebug() aFunction=0x%x"),aFunction);
       
   851 	if(!(aFunction&KDebugNotifyMask))
       
   852 		return;
       
   853 	iDebugQue.CheckDebug(aFunction);
       
   854 	}
       
   855 
       
   856 void FsNotify::HandleDismount(TNotifyDismountMode aMode, TInt aDrive, TBool aRemove, TInt err)
       
   857 //
       
   858 // Handle dismount notifications for the given drive
       
   859 //
       
   860 	{
       
   861 	__PRINT4(_L("FsNotify::HandleDismount() aMode = %d, aDrive=%d, aRemove=%d, err=%d"),aMode,aDrive,aRemove,err);
       
   862 	iDismountNotifyQue.CheckDismount(aMode, aDrive, aRemove, err);
       
   863 	}
       
   864 
       
   865 TBool FsNotify::HandlePendingDismount(CSessionFs* aSession, TInt aDrive)
       
   866 //
       
   867 // Checks if the session has an outstanding notification registered on the drive
       
   868 //
       
   869 	{
       
   870 	__PRINT1(_L("FsNotify::HandlePendingDismount() aDrive=%d"),aDrive);
       
   871 	return iDismountNotifyQue.HandlePendingDismount(aSession, aDrive);
       
   872 	}
       
   873 
       
   874 void FsNotify::DiskChange(TInt aDrive)
       
   875 //
       
   876 // Complete all notifications in queus due to a disk change
       
   877 //
       
   878 	{
       
   879 	__ASSERT_DEBUG((aDrive>=EDriveA && aDrive<=EDriveZ),Fault(EDiskChangeDrive));
       
   880 	__PRINT1(_L("FsNotify::DiskChange() aDrive=%d"),aDrive);
       
   881 	iChangeQues[ChangeIndex(aDrive)].CancelAll(KErrNone);
       
   882 	iChangeQues[ChangeIndex(KDriveInvalid)].CancelAll(KErrNone);
       
   883 	iDiskSpaceQues[aDrive].CancelAll(KErrNone);
       
   884 	iDebugQue.CancelAll(KErrNone);
       
   885 
       
   886 	// if there are any files containing dirty data, start issuing write-dirty data requests to trigger
       
   887 	// a critical notifier (CFileCache::HandleWriteDirtyError())
       
   888 	// otherwise purge all file caches
       
   889 	TDrive& drive=TheDrives[aDrive];
       
   890 	drive.FlushCachedFileInfo(ETrue);	
       
   891 	}
       
   892 
       
   893 	
       
   894 void FsNotify::CancelChangeSession(CSessionFs* aSession,TRequestStatus* aStatus)
       
   895 //
       
   896 //	Cancel change notifcation(s) setup by aSession and matching aStatus if not NULL
       
   897 //
       
   898 	{
       
   899 	__PRINT2(_L("FsNotify::CancelChangeSession() aSession=0x%x aStatus=0x%x"),aSession,aStatus);
       
   900 	for(TInt i=0;i<KMaxNotifyQues;++i)
       
   901 		{
       
   902 		TBool isFound=iChangeQues[i].CancelSession(aSession,KErrCancel,aStatus);
       
   903 		if(aStatus && isFound)
       
   904 			break;
       
   905 		}
       
   906 	}
       
   907 
       
   908 void FsNotify::CancelDiskSpaceSession(CSessionFs* aSession,TRequestStatus* aStatus)
       
   909 //
       
   910 // Cancel disk space notification(s) setup by aSession and matching aStatus if not NULL
       
   911 //
       
   912 
       
   913 	{
       
   914 	__PRINT2(_L("FsNotify::CancelDiskSpaceSession() aSession=0x%x aStatus=0x%x"),aSession,aStatus);
       
   915 	for(TInt i=0;i<KMaxDiskQues;++i)
       
   916 		{
       
   917 		TBool isFound=iDiskSpaceQues[i].CancelSession(aSession,KErrCancel,aStatus);
       
   918 		if(aStatus && isFound)
       
   919 			break;
       
   920 		}
       
   921 	}
       
   922 
       
   923 void FsNotify::CancelDebugSession(CSessionFs* aSession, TRequestStatus* aStatus)
       
   924 //
       
   925 // Cancel debug notification(s) setup by aSession and matching aStatus if not NULL
       
   926 //
       
   927 	{
       
   928 	__PRINT2(_L("FsNotify::CancelDebugSession() aSession=0x%x aStatus=0x%x"),aSession,aStatus);
       
   929 	iDebugQue.CancelSession(aSession,KErrCancel,aStatus);
       
   930 	}
       
   931 
       
   932 void FsNotify::CancelDismountNotifySession(CSessionFs* aSession, TRequestStatus* aStatus)
       
   933 //
       
   934 // Cancel all media removal notification(s) setup by aSession (if aStatus == NULL)
       
   935 // else cancels all oustanding notifications(s) for the session
       
   936 //
       
   937 	{
       
   938 	__PRINT2(_L("FsNotify::CancelDismountNotifySession() aSession=0x%x aStatus=0x%x"),aSession,aStatus);
       
   939 	iDismountNotifyQue.CancelSession(aSession,KErrCancel,aStatus);
       
   940 	}
       
   941 
       
   942 void FsNotify::CancelSession(CSessionFs* aSession)
       
   943 //
       
   944 //
       
   945 //
       
   946 	{
       
   947 	__PRINT(_L("FsNotify::CancelSession"));
       
   948 	FsNotify::CancelChangeSession(aSession);
       
   949 	FsNotify::CancelDiskSpaceSession(aSession);
       
   950 	FsNotify::CancelDebugSession(aSession);
       
   951 	FsNotify::CancelDismountNotifySession(aSession);
       
   952 	}
       
   953 
       
   954 
       
   955 TInt FsNotify::ChangeIndex(TInt aDrive)
       
   956 //
       
   957 //
       
   958 //
       
   959 	{
       
   960 	__ASSERT_DEBUG((aDrive>=EDriveA && aDrive<=EDriveZ) || aDrive==KDriveInvalid,Fault(EChangeBadIndex));
       
   961 	if(aDrive==KDriveInvalid)
       
   962 		return(0);
       
   963 	else
       
   964 		return(aDrive+1);
       
   965 	}
       
   966