Update contrib.
1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // f32\sfile\sf_notifier.cpp
18 #include "sf_notifier.h"
19 #include "sf_file_cache.h"
21 CFsObjectCon* FsNotificationManager::iNotifyRequests = NULL;
22 RFastLock FsNotificationManager::iChainLock;
23 TInt FsNotificationManager::iFilterRegister[];
24 CFsPool<CFsNotificationBlock>* FsNotificationManager::iPool;
27 CFsNotificationPathFilter* CFsNotificationPathFilter::NewL(const TDesC& aPath, const TDesC& aFilename)
29 CFsNotificationPathFilter* self = new (ELeave) CFsNotificationPathFilter();
30 CleanupStack::PushL(self);
31 self->ConstructL(aPath,aFilename);
32 CleanupStack::Pop(self);
36 void CFsNotificationPathFilter::ConstructL(const TDesC& aPath, const TDesC& aFilename)
38 //Allocate the path and filename
39 iPath = aPath.AllocL();
40 iFilename = aFilename.AllocL();
43 CFsNotificationPathFilter::~CFsNotificationPathFilter()
51 CFsNotificationPathFilter::CFsNotificationPathFilter()
52 : iPath(NULL), iFilename(NULL)
56 CFsNotifyRequest* CFsNotifyRequest::NewL()
58 CFsNotifyRequest* self = new(ELeave) CFsNotifyRequest();
59 CleanupStack::PushL(self);
65 void CFsNotifyRequest::ConstructL()
67 User::LeaveIfError(iClientSyncLock.CreateLocal());
68 User::LeaveIfError(iTailSemaphore.CreateLocal());
71 CFsNotifyRequest::CFsNotifyRequest()
76 CFsNotifyRequest::~CFsNotifyRequest()
78 __PRINT(_L("CFsNotifyRequest::~CFsNotifyRequest()"));
82 if(ClientMsgHandle()!=0)
83 iClientMsg.Complete(KErrCancel);
85 if(iBufferMsg.Handle()!=0)
86 iBufferMsg.Complete(KErrCancel);
88 iClientSyncLock.Close();
89 iTailSemaphore.Close();
93 * Returns the Array of TypeFilters.
94 * Each TFsNotificationTypeFilter matches to a particular TFsNotification::TFsNotificationType
95 * and has a CFsNotificationFilter which stores the iPath and iName associated with this filter type.
97 * (These are speerated so that we can have multiple type filters for every name filter)
99 TFsNotificationTypeArray* CFsNotifyRequest::FilterTypeList(TInt aDrive,TInt aIndex)
101 __ASSERT_DEBUG(aIndex < KNumRegisterableFilters,Fault(ENotificationFault));
103 TFsNotificationTypeDriveArray* filters = iDrivesTypesFiltersMap.Find(aDrive);
105 return &((*filters)[aIndex]);
110 //Sets filter's notification request status
111 void CFsNotifyRequest::SetActive(TNotifyRequestStatus aValue)
113 iNotifyRequestStatus = aValue;
116 CFsNotifyRequest::TNotifyRequestStatus CFsNotifyRequest::ActiveStatus()
118 return (TNotifyRequestStatus)iNotifyRequestStatus;
121 //Completes and frees notification request
122 //In case of KErrNone must be called with iChainLock already held
123 void CFsNotifyRequest::CompleteClientRequest(TInt aReason,TBool aIsCancel)
125 __PRINT(_L("CFsNotifyRequest::CompleteClientRequest()"));
127 iClientSyncLock.Wait();
129 if(aReason==KErrNone)
131 __PRINT(_L("CFsNotifyRequest::CompleteClientRequest() - Complete KErrNone"));
132 //Synchronising the current iServerTail to the client.
133 iClientHead = iClientTail; //Client has read all previous entries
134 iClientTail = iServerTail; //Client's new tail is everything the server has been writing since this function was last called
135 TInt clientTail = iClientTail;
136 TPckg<TInt> tailDes(clientTail);
137 iClientMsg.Write(KMsgPtr0,tailDes);
141 __PRINT(_L("CFsNotifyRequest::CompleteClientRequest() - Complete isCancel"));
145 TPckgBuf<TInt> tailDes(iClientTail);
146 //Perhaps client has crashed so no point checking return:
147 iClientMsg.Write(KMsgPtr0,tailDes);
149 __PRINT(_L("CFsNotifyRequest::CompleteClientRequest() - Complete Request"));
150 iClientMsg.Complete(aReason);
151 iClientSyncLock.Signal();
154 TInt CFsNotifyRequest::SynchroniseBuffer(CFsNotificationBlock& aBlock,TInt aServerTail, TInt aNotificationSize)
156 TPtrC8 blockDes((TText8*)aBlock.Data(),aNotificationSize);
157 return iBufferMsg.Write(KMsgPtr0,blockDes,aServerTail);
160 //Removes all filters.
161 //Deletes iPath, iFilename
162 TInt CFsNotifyRequest::RemoveFilters()
164 __PRINT(_L("CFsNotifyRequest::RemoveFilters()"));
166 //For every drive with filters set...
167 RHashMap<TInt,TFsNotificationTypeDriveArray>::TIter iterator(iDrivesTypesFiltersMap);
168 TFsNotificationTypeDriveArray* currentDriveFilters = (TFsNotificationTypeDriveArray*)iterator.NextValue();
169 while(currentDriveFilters)
171 //For every filter array (1 for each type of TFsNotificationType)
172 for(TInt filterType = 0; filterType < KNumRegisterableFilters; filterType++)
174 TFsNotificationTypeArray& filterList = (*currentDriveFilters)[filterType];
175 TInt filterTypeCount = filterList.Count();
178 //Remove this type from the filter register
179 TFsNotification::TFsNotificationType type = FsNotificationHelper::NotificationType(filterType);
180 FsNotificationManager::SetFilterRegister(type,EFalse,filterTypeCount);
185 currentDriveFilters->Reset();
186 currentDriveFilters->Close();
187 iterator.RemoveCurrent();
188 currentDriveFilters = (TFsNotificationTypeDriveArray*)iterator.NextValue();
190 iDrivesTypesFiltersMap.Close();
191 iPathFilterList.ResetAndDestroy();
192 iPathFilterList.Close();
196 TInt CFsNotifyRequest::AddFilterL(CFsNotificationPathFilter* aFilter, TUint aMask)
198 __PRINT(_L("CFsNotifyRequest::AddFilterL"));
200 iPathFilterList.AppendL(aFilter);
202 //Get the drive number to so know which drive array to add the filter(s) to.
203 TInt driveNum = FsNotificationHelper::DriveNumber(aFilter->iPath->Des());
207 //Create/Add a TypeFilter for each type in aMask
208 while((notifyType & KNotificationValidFiltersMask) && (aMask & KNotificationValidFiltersMask))
210 //If this notifyType is present in aMask
211 if(aMask & notifyType)
213 TFsNotificationTypeFilter typeFilter;
214 typeFilter.iNotificationType = (TFsNotification::TFsNotificationType) notifyType;
215 typeFilter.iPathFilter = aFilter;
216 TInt index = FsNotificationHelper::TypeToIndex(typeFilter.iNotificationType);
218 //If the per-drive-filterLists have not
219 //been set up yet then do so now.
220 TFsNotificationTypeDriveArray* driveArray = iDrivesTypesFiltersMap.Find(driveNum);
223 TFsNotificationTypeDriveArray dArray;
224 r = iDrivesTypesFiltersMap.Insert(driveNum,dArray);
225 User::LeaveIfError(r);
226 driveArray = iDrivesTypesFiltersMap.Find(driveNum);
228 //Create filter arrays for every type
229 for(TInt i =0; i< KNumRegisterableFilters; i++)
231 TFsNotificationTypeArray filterArray;
232 driveArray->Append(filterArray);
235 TFsNotificationTypeArray& filterArray= (*driveArray)[index];
236 filterArray.Append(typeFilter);
238 //Remove this type from our mask
247 TInt CFsNotifyRequest::SetClientMessage(const RMessage2& aClientMsg)
249 __PRINT(_L("CFsNotifyRequest::SetClientMessage"));
250 iClientMsg = aClientMsg;
254 TInt CFsNotifyRequest::ClientMsgHandle()
256 return iClientMsg.Handle();
259 void CFsNotifyRequest::CloseNotification()
261 __PRINT(_L("CFsNotifyRequest::CloseNotification()"));
262 iBufferMsg.Complete(KErrNone);
263 if(ClientMsgHandle()!=0)
264 CompleteClientRequest(KErrCancel,EFalse);
267 //New notification request from client
268 void FsNotificationManager::AddNotificationRequestL(CFsNotifyRequest* aNotificationRequest)
270 __PRINT(_L("FsNotificationManager::AddNotificationRequestL"));
272 iNotifyRequests->AddL(aNotificationRequest,ETrue);
276 //Notification request cancelled
277 //Must be called with iChainLock held
278 void FsNotificationManager::RemoveNotificationRequest(CFsNotifyRequest* aNotificationRequest)
280 __PRINT(_L("FsNotificationManager::RemoveNotificationRequest"));
281 iNotifyRequests->Remove(aNotificationRequest,ETrue);
284 void FsNotificationManager::RemoveNotificationRequest(CSessionFs* aSession)
286 __PRINT(_L("FsNotificationManager::RemoveNotificationRequest(CSessionFs*)"));
288 TInt count = Count();
292 count = Count(); //check again just incase it's changed before we got the lock
295 for(TInt i=0; i < count; i++)
297 //Remove all notification requests associated with this session.
298 CFsNotifyRequest* notify = (CFsNotifyRequest*)(*iNotifyRequests)[i];
299 if(notify->iSession == aSession)
301 RemoveNotificationRequest(notify);
307 __PRINT(_L("FsNotificationManager::RemoveNotificationRequest(CSessionFs*) - Closing Manager"));
315 TBool FsNotificationManager::IsInitialised()
317 __PRINT(_L("FsNotificationManager::IsInitialised()"));
318 return (TBool)iNotifyRequests;
321 void FsNotificationManager::OpenL()
323 __PRINT(_L("FsNotificationManager::InitialiseL()"));
326 if(iChainLock.Handle() == 0)
328 User::LeaveIfError(iChainLock.CreateLocal());
330 iNotifyRequests = TheContainer->CreateL();
331 iPool = CFsPool<CFsNotificationBlock>::New(KNotificationPoolSize);
332 User::LeaveIfNull(iPool);
336 void FsNotificationManager::SetFilterRegister(TUint aFilter, TBool aAdd, TInt aCount)
338 __PRINT2(_L("FsNotificationManager::SetFilterRegister(aFilter=%u,aAdd=%d)"),aFilter,aAdd);
339 TInt index = FsNotificationHelper::TypeToIndex((TFsNotification::TFsNotificationType)aFilter);
340 TInt& fr = FsNotificationManager::FilterRegister(index);
341 __ASSERT_DEBUG((aAdd) ? fr >= 0 : fr > 0,Fault(ENotificationFault));
342 fr+= aAdd ? aCount : -aCount;
345 void FsNotificationManager::SetFilterRegisterMask(TUint aMask,TBool aAdd)
347 __PRINT(_L("FsNotificationManager::RegisterFilterMask()"));
350 while(notifyType & KNotificationValidFiltersMask && aMask & KNotificationValidFiltersMask)
352 if(aMask & notifyType)
354 SetFilterRegister(notifyType,aAdd);
361 TInt& FsNotificationManager::FilterRegister(TInt aIndex)
363 __PRINT(_L("FsNotificationManager::FilterRegister()"));
364 __ASSERT_DEBUG(aIndex < KNumRegisterableFilters,Fault(ENotificationFault));
365 return iFilterRegister[aIndex];
368 //Must be called with the iChainLock
369 void FsNotificationManager::Close()
371 __PRINT(_L("FsNotificationManager::Stop()"));
372 CFsObjectCon*& request = iNotifyRequests;
375 TheContainer->Delete(request);
382 TInt FsNotificationManager::Count()
384 __PRINT(_L("FsNotificationManager::Count()"));
386 return iNotifyRequests->Count();
390 void FsNotificationManager::Lock()
392 __PRINT(_L("--->FsNotificationManager::Lock()"));
396 void FsNotificationManager::Unlock()
398 __PRINT(_L("<---FsNotificationManager::Unlock()"));
402 //Get the notification type based on the TFsMessage function
403 void FsNotificationHelper::NotificationType(TInt aFunction,TFsNotification::TFsNotificationType& aNotificationType)
405 __PRINT(_L("FsNotificationHelper::NotificationType"));
409 case EFsFileWriteDirty:
412 aNotificationType = TFsNotification::EFileChange;
419 aNotificationType = TFsNotification::ERename;
426 aNotificationType = TFsNotification::ECreate;
433 aNotificationType = TFsNotification::EAttribute;
439 aNotificationType = TFsNotification::EDelete;
444 aNotificationType = TFsNotification::EVolumeName;
447 case EFsSetDriveName:
449 aNotificationType = TFsNotification::EDriveName;
452 case EFsDismountFileSystem:
453 case EFsMountFileSystem:
455 case EFsRawDiskWrite:
456 case EFsMountFileSystemScan:
458 aNotificationType = TFsNotification::EMediaChange;
463 aNotificationType = (TFsNotification::TFsNotificationType)0;
469 //=====CFsNotificationBlock============================
472 CFsNotificationBlock* CFsNotificationBlock::New()
474 return new CFsNotificationBlock();
476 CFsNotificationBlock::CFsNotificationBlock()
479 CFsNotificationBlock::~CFsNotificationBlock()
483 TAny* CFsNotificationBlock::Data()
485 return (TAny*)&iData;
489 //=====FsNotificationManager===========================
491 //Get the path of the file, folder or drive name based on the TFsMessage function
492 void FsNotificationHelper::PathName(CFsClientMessageRequest& aRequest, TDes& aPath)
494 __PRINT(_L("FsNotificationHelper::PathName"));
495 //Get the notification type
496 TInt function = aRequest.Operation()->Function();
498 //Get the filename(s)
501 case EFsFileWrite: //EParseSrc | EFileShare
502 case EFsFileSetSize: //EParseSrc | EFileShare
503 case EFsFileSetAtt: //EParseDst | EParseSrc, - should not use these; has share.
505 case EFsFileWriteDirty: //EFileShare
507 CFileShare* share = NULL;
508 CFileCB* file = NULL;
509 GetFileFromScratch(&aRequest,share,file);
510 aPath.Append(file->DriveNumber() + 'A');
512 aPath.Append(file->FileName().Des());
515 case EFsFileCreate: //EParseSrc
516 case EFsDelete: //EParseSrc
517 case EFsSetEntry: //EParseSrc,
518 case EFsFileRename: //EParseDst | EParseSrc,
519 case EFsRename: //EParseDst | EParseSrc,
520 case EFsReplace: //EParseDst | EParseSrc,
521 case EFsFileReplace: //EParseSrc
523 aPath.Copy(aRequest.Src().FullName());
526 case EFsRmDir: //EParseSrc
527 case EFsMkDir: //EParseSrc
529 aPath.Copy(aRequest.Src().DriveAndPath());
532 case EFsFormatNext: //EParseSrc
533 case EFsDismountFileSystem: //0
534 case EFsMountFileSystem: //0
535 case EFsSetVolume: //0
536 case EFsSetDriveName: //ESync
537 case EFsRawDiskWrite: //EParseSrc
538 case EFsMountFileSystemScan:
540 _LIT(KFormatDrive,"?:");
542 drive.Append(KFormatDrive);
543 drive[0] = TText(aRequest.Drive()->DriveNumber() + 'A');
553 //Get the new path of the file, folder or drive name based on the TFsMessage function
554 void FsNotificationHelper::NewPathName(CFsClientMessageRequest& aRequest, TPtrC& aNewPath)
556 __PRINT(_L("FsNotificationHelper::NewPathName"));
557 //Get the notification type
558 TInt function = aRequest.Operation()->Function();
560 //Get the filename(s)
563 case EFsFileRename: //EParseDst | EParseSrc,
564 case EFsRename: //EParseDst | EParseSrc,
565 case EFsReplace: //EParseDst | EParseSrc,
567 aNewPath.Set(aRequest.Dest().FullName());
570 case EFsSetDriveName: //ESync
573 aRequest.ReadL(KMsgPtr1, name);
577 case EFsSetVolume: //0
580 aRequest.ReadL(KMsgPtr0, name);
592 //Get the size of the notification based on its type
593 TInt FsNotificationHelper::NotificationSize(CFsClientMessageRequest& aRequest, TFsNotification::TFsNotificationType aNotificationType, const TDesC& aName)
595 __PRINT(_L("FsNotificationHelper::NotificationSize"));
598 * If there are no new names, the order of the data in the buffer is:
599 * Word1 : NotificationSize (2 bytes) , PathSize (2 bytes)
600 * Word2 : NotificationType (Lower 2 bytes)
601 * Word(s) : Path (TText8) , [Any sub-class members]
603 * Else for notification types ERename, EVolumeName and EDriveName the order is:
604 * Word1 : NotificationSize (2 bytes) , PathSize (2 bytes)
605 * Word2 : NewNameSize (2 bytes) , NotificationType (2 bytes)
606 * Word(s) : Path (TText8) , NewName (TText8)
608 * EOverflow size: KNotificationHeaderSize
611 TInt size = KNotificationHeaderSize + Align4(aName.Size());
613 switch(aNotificationType)
616 case TFsNotification::ERename:
617 case TFsNotification::EVolumeName:
618 case TFsNotification::EDriveName:
621 NewPathName(aRequest,dest);
622 size += Align4(dest.Size());
625 case TFsNotification::EFileChange:
627 size += sizeof(TInt64);
630 case TFsNotification::EAttribute:
632 size += sizeof(TUint64);
635 case TFsNotification::ECreate:
636 case TFsNotification::EDelete:
637 case TFsNotification::EMediaChange:
647 return (TUint16) size;
650 TFsNotification::TFsNotificationType FsNotificationHelper::NotificationType(TInt& aIndex)
652 __PRINT(_L("FsNotificationHelper::NotificationType(TInt)"));
653 __ASSERT_DEBUG(aIndex < KNumRegisterableFilters, Fault(ENotificationFault));
655 switch(aIndex) //No break statements here on purpose
657 case 7 : return TFsNotification::EMediaChange;
658 case 6 : return TFsNotification::EDriveName;
659 case 5 : return TFsNotification::EVolumeName;
660 case 4 : return TFsNotification::EDelete;
661 case 3 : return TFsNotification::EAttribute;
662 case 2 : return TFsNotification::ECreate;
663 case 1 : return TFsNotification::ERename;
664 case 0 : return TFsNotification::EFileChange;
665 default: ASSERT(0); return (TFsNotification::TFsNotificationType) 0;
669 //Get the array index of the notification based on its type
670 TInt FsNotificationHelper::TypeToIndex(TFsNotification::TFsNotificationType aType)
672 __PRINT(_L("FsNotificationHelper::ArrayIndex"));
675 switch(aType) //No break statements here on purpose
677 case TFsNotification::EMediaChange: index++;
678 case TFsNotification::EDriveName: index++;
679 case TFsNotification::EVolumeName: index++;
680 case TFsNotification::EDelete: index++;
681 case TFsNotification::EAttribute: index++;
682 case TFsNotification::ECreate: index++;
683 case TFsNotification::ERename: index++;
684 case TFsNotification::EFileChange: // skip;
687 __ASSERT_DEBUG(index < KNumRegisterableFilters, Fault(ENotificationFault));
691 TInt FsNotificationHelper::DriveNumber(const TPtrC& aPath)
693 if(aPath.Length() >= 2 && ((TChar)aPath[1])==(TChar)':')
695 TChar driveChar = ((TChar)aPath[0]);
696 driveChar.UpperCase();
697 TInt driveNum = driveChar-(TChar)'A';
706 //Get the attributes set and cleared
707 void FsNotificationHelper::Attributes(CFsClientMessageRequest& aRequest, TUint& aSet, TUint& aClear)
709 __PRINT(_L("FsNotificationHelper::Attributes"));
711 TInt function = aRequest.Operation()->Function();
712 const RMessage2& msg = aRequest.Message();
743 TBool CFsNotifyRequest::ValidateNotification(TInt aNotificationSize, TInt& aServerTail)
745 __PRINT(_L("CFsNotifyRequest::ValidateNotification"));
746 //RDebug::Print(_L("CFsNotifyRequest::ValidateNotification - iServerTail=%d, aServerTail=%d, iClientTail=%d,iClientHead=%d, aNotificationSize=%d"),iServerTail,aServerTail,iClientTail,iClientHead,aNotificationSize);
750 TBool overflow = EFalse;
752 //Check that we have not filled the buffer
753 if (aServerTail == iClientHead)
755 // Buffer is empty when Client Tail = Client Head
756 if (iClientHead != iClientTail)
763 //Work out remaining size taking account of whether the end position is
764 //before or after the overflow position.
765 TInt remainingSize = (iClientHead > aServerTail)
766 ? iClientHead - aServerTail
767 : iClientBufferSize - (aServerTail - iClientHead);
769 TInt reservedSize = aNotificationSize;
770 // + Save additional space for OVERFLOW
771 reservedSize += KNotificationHeaderSize;
774 // Have we wrapped around already?
776 if (iClientHead > aServerTail)
779 // Buffer looks something like this:
786 // Check if we can insert in the middle section:
788 if (remainingSize < reservedSize)
794 // We add new notification to middle
803 // We have not wrapped around yet..
805 // Buffer looks something like this:
814 // Check up-front whether its possible for overflow to go at the beginning.
815 // If there is not enough space at the start for overflow then we need to
816 // check that's there's space for overflow at the end and must not rollover.
818 TBool canRollOver = ETrue;
820 if (iClientHead < KNotificationHeaderSize)
827 // No space for overflow at the beginning of buffer.
829 canRollOver = EFalse;
833 // IF: Cannot rollover
837 //IF (notification + overflow) does not fit at the end overflow now.
838 if ((iClientBufferSize - aServerTail) < reservedSize)
844 // Add notification (**) to end [---12345678**---]
850 // - need to check that notification fits at the end
851 // or that notification+overflow fits at the beginning.
853 // If not enough space at end, rollover
854 if ((iClientBufferSize - aServerTail) < aNotificationSize)
857 // Add notification to start and fill end with Filler char
861 // IF we are not at the very end of the buffer,
862 // insert a KNotificationBufferFiller at iServerTail.
863 // When the client reads this, it sets iHead to 0 and reads from there.
864 if(iServerTail != iClientBufferSize)
866 //If there is space it will always be at least 1 word big
867 TPtrC8 fillerDes((TText8*) &KNotificationBufferFiller, sizeof(TUint));
868 iBufferMsg.Write(KMsgPtr0, fillerDes, aServerTail);
871 // Now that we have rolled over we need to check whether there is
872 // space at the beginning for notification + overflow
873 // We already know that overflow fits.
874 if (reservedSize > iClientHead)
880 // Add notification/overflow to the beginning
881 // [**--0123456789(#)]
886 // else - notification fits at the end so there is nothing to do here.
896 // Called from FsNotificationManager::HandleChange().
897 // Sends notifications into the client's buffer.
898 // If there is a iClientMsg then this is the first time this
899 // has been called since the client called RequestNotifications.
900 // In this situation we complete the client request.
901 TInt CFsNotifyRequest::NotifyChange(CFsClientMessageRequest* aRequest,const TDesC& aName, TFsNotification::TFsNotificationType aNotificationType, CFsNotificationBlock& aBlock)
904 * Different notification types have different data associated with them.
906 * All types EXCEPT for ERename, EVolumeName and EDriveName have the following data
907 * and are aligned in the buffer like so:
908 * Word1 : NotificationSize (2 bytes) , PathSize (2 bytes)
909 * Word2 : NotificationType (Lower 2 bytes)
910 * Word(s) : Path (TText8) , [Any sub-class members]
912 * Else for notification types ERename, EVolumeName and EDriveName the order is:
913 * Word1 : NotificationSize (2 bytes) , PathSize (2 bytes)
914 * Word2 : NewNameSize (2 bytes) , NotificationType (2 bytes)
915 * Word(s) : Path (TText8) , NewName (TText8)
917 * Overflow notification type doesn't have a name, so its namesize is 0
918 * and there will be no Word3.
921 __PRINT(_L("CFsNotifyRequest::NotifyChange()"));
923 TInt notificationSize = FsNotificationHelper::NotificationSize(*aRequest,aNotificationType,aName);
925 iClientSyncLock.Wait();
926 iTailSemaphore.Wait();
928 TInt tail = iServerTail;
931 TBool overflow = ValidateNotification(notificationSize, tail);
933 //Now that we know there is enough space in the buffer we can write
934 //the standard attributes that all notifications have.
936 //We can store the size of the notification
937 //and the size of the name in the same word.
939 TUint16 nameLen = 0; //Overflow has no name
940 TInt notifSize = KNotificationHeaderSize;
943 nameLen = (TUint16)aName.Size();
944 notifSize = notificationSize;
948 aNotificationType = TFsNotification::EOverflow;
951 iServerTail = tail + notifSize;
952 iTailSemaphore.Signal();
954 TInt writeOffset = 0; //Where to write in the block
956 //Store notification Size and NameSize (Word1)
957 TUint sizeNameLen = (notifSize << 16) | nameLen;
958 memcpy((TText8*)aBlock.Data()+writeOffset,&sizeNameLen,sizeof(TUint));
959 writeOffset+=sizeof(TUint);
963 if (aNotificationType == TFsNotification::ERename ||
964 aNotificationType == TFsNotification::EVolumeName ||
965 aNotificationType == TFsNotification::EDriveName)
967 FsNotificationHelper::NewPathName(*aRequest,newName);
968 //Store NewNameSize and notification Type (Word2)
969 TUint typeNewNameLen = ((TUint16)newName.Size() << 16) | (TUint16)aNotificationType;
970 memcpy((TText8*)aBlock.Data()+writeOffset,&typeNewNameLen,sizeof(TUint));
974 //Store notification Type (Word2)
975 memcpy((TText8*)aBlock.Data()+writeOffset,&aNotificationType,sizeof(TUint));
977 writeOffset+=sizeof(TUint);
979 CFileShare* share = NULL;
980 CFileCB* file = NULL;
981 if(aRequest) //Don't always have a request such as when called from localdrives.
983 GetFileFromScratch(aRequest, share, file);
990 uid.iUid = KErrUnknown;
991 if(aRequest && aRequest->Operation()->iFunction == EFsFileWriteDirty)
993 uid = aRequest->iUID;
997 uid = aRequest->Message().Identity();
999 memcpy((TText8*)aBlock.Data()+writeOffset,&uid.iUid,sizeof(TUint32));
1000 writeOffset+=sizeof(TUint32);
1005 //Store Name (Word3)
1006 memcpy((TText8*)aBlock.Data()+writeOffset,aName.Ptr(),aName.Size());
1007 writeOffset += Align4(aName.Size());
1010 switch (aNotificationType)
1012 case TFsNotification::EFileChange:
1015 size = file->CachedSize64();
1016 memcpy((TText8*)aBlock.Data()+writeOffset,&size,sizeof(TInt64));
1017 writeOffset += sizeof(TInt64);
1020 case TFsNotification::ERename:
1021 case TFsNotification::EVolumeName:
1022 case TFsNotification::EDriveName:
1025 memcpy((TText8*)aBlock.Data()+writeOffset,newName.Ptr(),newName.Size());
1026 writeOffset += Align4(newName.Size());
1029 case TFsNotification::EAttribute:
1033 FsNotificationHelper::Attributes(*aRequest,set,clear);
1034 TUint64 att = MAKE_TUINT64(set,clear);
1035 memcpy((TText8*)aBlock.Data()+writeOffset,&att,sizeof(TUint64));
1036 writeOffset += sizeof(TUint64);
1046 //Write to client buffer
1047 TInt r = SynchroniseBuffer(aBlock,tail,notifSize);
1049 //Signal the iClientSyncLock.
1050 //When all locks on this are signaled then CompleteClientRequest can be called.
1051 //This signal moves when we have a cache system
1052 iClientSyncLock.Signal();
1054 //We need to complete if this was the first
1055 //write to the client's buffer
1058 //We need to complete if this was the first
1059 //write to the client's buffer
1060 if(ClientMsgHandle()!=0)
1062 //RDebug::Print(_L("CFsNotifyRequest::NotifyChange iClientHead(%d) iClientTail(%d) iServerTail(%d) iClientBufferSize(%d)"),iClientHead,iClientTail,iServerTail,iClientBufferSize);
1063 __PRINT4(_L("CFsNotifyRequest::NotifyChange iClientHead(%d) iClientTail(%d) iServerTail(%d) iClientBufferSize(%d)"),iClientHead,iClientTail,iServerTail,iClientBufferSize);
1064 CompleteClientRequest(KErrNone);
1068 SetActive(CFsNotifyRequest::EOutstanding);
1072 SetActive(CFsNotifyRequest::EOutstandingOverflow);
1077 //RDebug::Print(_L("sf_notifier.cpp line %d function = %d, r = %d"),__LINE__, aRequest->FsFunction(),r);
1078 //RDebug::Print(_L("iServerTail=%d, tail=%d, iClientBufferSize=%d, overflow=%d"),iServerTail,tail,iClientBufferSize,overflow);
1083 #ifdef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
1085 //A change has occurred in f32 represented by this
1086 //request object. Work out which CfsNotify’s are interested
1087 // (if any) and call CfsNotifyRequest::NotifyChange.
1088 void FsNotificationManager::HandleChange(CFsClientMessageRequest* aRequest,const TDesC& aOperationName, TFsNotification::TFsNotificationType aType)
1090 __PRINT2(_L("FsNotificationManager::HandleChange() aRequest=0x%x, aType=%d"),&aRequest,aType);
1092 Lock(); //ToDo: Read Lock (Read/Write Lock)
1095 //Only search while there are filters of this type set up.
1096 TInt index = FsNotificationHelper::TypeToIndex(aType);
1097 TInt& filterCount = FsNotificationManager::FilterRegister(index);
1098 TInt seenFilter = filterCount; //Number of requests set up for this type
1100 //Iterate CFsNotifyRequests
1101 TInt count = iNotifyRequests->Count();
1103 if(aType == TFsNotification::EMediaChange)
1106 //If there aren't any requests then breakout
1113 TInt driveNum = FsNotificationHelper::DriveNumber(aOperationName);
1115 //For every notification request.
1116 for(TInt i=0; i<count && seenFilter; ++i)
1118 CFsNotifyRequest* notifyRequest = (CFsNotifyRequest*)(*iNotifyRequests)[i];
1119 CFsNotifyRequest::TNotifyRequestStatus status = notifyRequest->ActiveStatus();
1120 if(! (status==CFsNotifyRequest::EActive ||
1121 status==CFsNotifyRequest::EOutstanding))
1123 //Not active; check next notification request
1127 //Check whether we are interested in this change.
1128 //Get the filters associated with this operation on this drive
1129 TFsNotificationTypeArray* filterList = notifyRequest->FilterTypeList(driveNum,index);
1130 DoHandleChange(filterList,seenFilter,aRequest,notifyRequest,aOperationName,aType);
1132 if(aType==TFsNotification::EMediaChange)
1133 continue; //next request
1135 //If there are still filters to check
1138 //Check changes that are not tied to a particular drive
1139 filterList = notifyRequest->FilterTypeList(KErrNotFound,index);
1140 DoHandleChange(filterList,seenFilter,aRequest,notifyRequest,aOperationName,aType);
1147 //A change has occurred in f32 represented by this
1148 //request object. Work out which CfsNotify’s are interested
1149 // (if any) and call CfsNotifyRequest::NotifyChange.
1150 void FsNotificationManager::HandleChange(CFsClientMessageRequest& aRequest, TFsNotification::TFsNotificationType aType)
1152 __PRINT(_L("FsNotificationManager::HandleChange"));
1153 TFileName currentOperationsName;
1154 FsNotificationHelper::PathName(aRequest, currentOperationsName);
1155 if(currentOperationsName.Length())
1156 HandleChange(&aRequest,currentOperationsName,aType);
1159 //A change has occurred in f32 represented by this
1160 //request object. Work out which CfsNotify’s are interested
1161 // (if any) and call CfsNotifyRequest::NotifyChange.
1162 void FsNotificationManager::HandleChange(CFsClientMessageRequest& aRequest)
1164 if(Count() && aRequest.Message().Handle() != KLocalMessageHandle)
1166 __PRINT(_L("FsNotificationManager::HandleChange"));
1167 TFsNotification::TFsNotificationType operationNotificationType;
1168 FsNotificationHelper::NotificationType(aRequest.FsFunction(), operationNotificationType);
1169 HandleChange(aRequest,operationNotificationType);
1178 void FsNotificationManager::HandleChange(CFsClientMessageRequest* ,const TDesC&, TFsNotification::TFsNotificationType)
1183 void FsNotificationManager::HandleChange(CFsClientMessageRequest& , TFsNotification::TFsNotificationType)
1188 void FsNotificationManager::HandleChange(CFsClientMessageRequest&)
1193 #endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
1195 //Called from FsNotificationManager::DoHandleChange
1196 FsNotificationManager::TFsNotificationFilterMatch FsNotificationManager::DoMatchFilter(CFsClientMessageRequest* aRequest, const TDesC& aOperationName,CFsNotificationPathFilter& aFilter)
1198 TFsNotificationFilterMatch filterMatch = EDifferent;
1199 TParsePtrC parseOp(aOperationName);
1200 TPtrC pathOpDes = parseOp.DriveAndPath();
1201 TPtrC nameOpDes = parseOp.NameAndExt();
1202 TInt pathLength = aFilter.iPath->Des().Length();
1203 TInt nameLength = aFilter.iFilename->Des().Length();
1208 paths = pathOpDes.MatchF(aFilter.iPath->Des());
1210 else //if no path filter was set up
1211 // then we need to ensure we don't notify on data-caged areas which we shouldn't
1213 TInt r = PathCheck(aRequest,aOperationName.Mid(2),&KCapFsSysFileTemp,&KCapFsPriFileTemp,&KCapFsROFileTemp, __PLATSEC_DIAGNOSTIC_STRING("FsNotificationManager::DoHandleChange"));
1215 return EContinue; //next filter
1220 names = nameOpDes.MatchF(aFilter.iFilename->Des());
1222 //Check: Path & Names Match
1223 if((paths == 0 || pathLength==0) && // paths match &&
1224 (names >= 0 || (nameLength==0 && nameOpDes.Length()==0))) // names match OR there are no names (i.e. operation is a dir and no filename filter)
1226 filterMatch = EMatch;
1231 // This is called on a per drive basis.
1232 void FsNotificationManager::DoHandleChange(TFsNotificationTypeArray* aFilterTypeArray,TInt& aSeenFilter, CFsClientMessageRequest* aRequest, CFsNotifyRequest* aNotifyRequest, const TDesC& aOperationName, TFsNotification::TFsNotificationType& aType)
1234 __PRINT(_L("FsNotificationManager::DoHandleChange()"));
1236 if(!aFilterTypeArray)
1239 TInt numFilters = aFilterTypeArray->Count();
1241 if(aType == TFsNotification::EMediaChange)
1242 numFilters = 1; //Only need to notify once per drive.
1244 //For every filter in this request
1245 for(TInt j = 0; j < numFilters;++j)
1247 //Is the correct notification type
1250 TBool filterMatch = EDifferent;
1251 if(aType != TFsNotification::EMediaChange)
1253 CFsNotificationPathFilter& filter = *(((*aFilterTypeArray)[j]).iPathFilter);
1254 __PRINT2(_L("FsNotificationManager::DoHandleChange() operationName=%S, filterName=%S"),&aOperationName,filter.iPath);
1256 filterMatch = DoMatchFilter(aRequest,aOperationName,filter);
1257 if(filterMatch == FsNotificationManager::EContinue)
1258 continue; //triggers for data cages
1260 //We need to check for changes coming in to a directory when its rename
1261 if(aType == TFsNotification::ERename && filterMatch==FsNotificationManager::EDifferent)
1263 TPtrC aDestinationNamePtrC;
1264 FsNotificationHelper::NewPathName(*aRequest,aDestinationNamePtrC);
1265 __PRINT2(_L("FsNotificationManager::DoHandleChange() destinationName=%S, filterName=%S"),&aDestinationNamePtrC,filter.iPath);
1266 filterMatch = DoMatchFilter(aRequest,aDestinationNamePtrC,filter);
1270 if(filterMatch || (aType == TFsNotification::EMediaChange))//Match or MediaChange (report regardless of filters)
1272 //Matching - Handle change
1274 //Get a CFsNotificationBlock to use
1275 //So that we can do IPC from a single place.
1276 CFsNotificationBlock* block = iPool->Allocate();
1278 TInt r = aNotifyRequest->NotifyChange(aRequest,aOperationName,aType,*block);
1285 //Something went wrong writing to the client's buffer
1286 aNotifyRequest->SetActive(CFsNotifyRequest::EInactive);
1287 if(aNotifyRequest->ClientMsgHandle()!=0)
1288 aNotifyRequest->CompleteClientRequest(r,EFalse);
1289 break; //Go to outer for (i.e. next request in HandleChange)
1292 continue; //next filter