os/kernelhwsrv/userlibandfileserver/fileserver/sfile/sf_notify.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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