|
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 |