0
|
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".
|
|
7 |
//
|
|
8 |
// Initial Contributors:
|
|
9 |
// Nokia Corporation - initial contribution.
|
|
10 |
//
|
|
11 |
// Contributors:
|
|
12 |
//
|
|
13 |
// Description:
|
|
14 |
// f32\sfile\sf_notifier.h
|
|
15 |
//
|
|
16 |
//
|
|
17 |
|
|
18 |
#include "sf_std.h"
|
|
19 |
#include "sf_pool.h"
|
|
20 |
#include "e32hashtab.h"
|
|
21 |
#include "cl_notification.h"
|
|
22 |
#include "f32notification.h"
|
|
23 |
|
|
24 |
#ifndef SF_NOTIFIER_H
|
|
25 |
#define SF_NOTIFIER_H
|
|
26 |
|
|
27 |
/**
|
|
28 |
* Number of notifications in TFsNotificationType that the client can set
|
|
29 |
* @internalTechnology
|
|
30 |
*/
|
|
31 |
const TInt KNumRegisterableFilters = 8;
|
|
32 |
|
|
33 |
/*
|
|
34 |
* This determines the size of the CFsPool.
|
|
35 |
* Until we have read/write locks there is no point in this being more than 1.
|
|
36 |
*
|
|
37 |
* @internalTechnology
|
|
38 |
*/
|
|
39 |
const TInt KNotificationPoolSize = 1;
|
|
40 |
|
|
41 |
|
|
42 |
/**
|
|
43 |
* A CFsNotificationPathFilter is a simple class containing two HBufCs of the target to be notified about:
|
|
44 |
* 1 for the drive and path
|
|
45 |
* 1 for the filename
|
|
46 |
*
|
|
47 |
* A CFsNotificationPathFilter has a 1 to Many relationship with TFsNotificationTypeFilter
|
|
48 |
*
|
|
49 |
* @internalTechnology
|
|
50 |
*/
|
|
51 |
class CFsNotificationPathFilter
|
|
52 |
{
|
|
53 |
public:
|
|
54 |
static CFsNotificationPathFilter* NewL(const TDesC& aPath, const TDesC& aFilename);
|
|
55 |
~CFsNotificationPathFilter();
|
|
56 |
private:
|
|
57 |
void ConstructL(const TDesC& aPath, const TDesC& aFilename);
|
|
58 |
CFsNotificationPathFilter();
|
|
59 |
public:
|
|
60 |
HBufC* iPath;
|
|
61 |
HBufC* iFilename;
|
|
62 |
};
|
|
63 |
|
|
64 |
/**
|
|
65 |
* A TFsNotificationTypeFilter is a class which contains a pointer to the associated path to monitor
|
|
66 |
* and the type of notification.
|
|
67 |
*
|
|
68 |
* @internalTechnology
|
|
69 |
*/
|
|
70 |
class TFsNotificationTypeFilter
|
|
71 |
{
|
|
72 |
public:
|
|
73 |
CFsNotificationPathFilter* iPathFilter;
|
|
74 |
TFsNotification::TFsNotificationType iNotificationType;
|
|
75 |
//As we are storing filters in filter-specific
|
|
76 |
//arrays then iNotificationType is potentially redundant.
|
|
77 |
};
|
|
78 |
|
|
79 |
//These typedefs are to appease the compiler as it does not like
|
|
80 |
//nested templated arguments.
|
|
81 |
/**
|
|
82 |
* @internalTechnology
|
|
83 |
*/
|
|
84 |
typedef RArray<TFsNotificationTypeFilter> TFsNotificationTypeArray;
|
|
85 |
/**
|
|
86 |
* @internalTechnology
|
|
87 |
*/
|
|
88 |
typedef RArray<TFsNotificationTypeArray> TFsNotificationTypeDriveArray;
|
|
89 |
|
|
90 |
class CFsNotificationBlock; //forward decl.
|
|
91 |
|
|
92 |
/**
|
|
93 |
* CFsNotifyRequest is a file-server side object representation of an RFsNotify sub-session.
|
|
94 |
*
|
|
95 |
* @internalTechnology
|
|
96 |
*/
|
|
97 |
NONSHARABLE_CLASS(CFsNotifyRequest) : public CFsObject
|
|
98 |
{
|
|
99 |
public:
|
|
100 |
|
|
101 |
/*
|
|
102 |
* Active means that the client is waiting for the first notification to be sent
|
|
103 |
* The status then changes to Outstanding when further notifications are sent to the buffer
|
|
104 |
* If the server overflows when in state EOutstanding then we move to state EOutstandingOverflow.
|
|
105 |
* From EOutstandingOverflow after the next call to RequestNotifications from the client, we must move to state EInactive.
|
|
106 |
* If we do not overflow then when RequestNotifications is called we can move back to state EActive.
|
|
107 |
* EInactive is when there are no notifications outstanding and request notifications hasn't been called.
|
|
108 |
*/
|
|
109 |
enum TNotifyRequestStatus
|
|
110 |
{
|
|
111 |
EActive, //Server waiting for a notification (filters added, RequestNotifications called)
|
|
112 |
EOutstanding, //Server waiting for client to call RequestNotifications, has notification(s) to send.
|
|
113 |
EOutstandingOverflow, //Server waiting for client to call RequestNotifications, has notification(s) to send, buffer has overflowed.
|
|
114 |
EInactive //Server waiting for RequestNotification, no notifications outstanding
|
|
115 |
};
|
|
116 |
|
|
117 |
static CFsNotifyRequest* NewL();
|
|
118 |
virtual ~CFsNotifyRequest();
|
|
119 |
|
|
120 |
/*
|
|
121 |
* Returns the RArray<TFsNotificationFilter> for an index
|
|
122 |
* as returned from FsNotificationHelper::TypeToIndex()
|
|
123 |
*/
|
|
124 |
TFsNotificationTypeArray* FilterTypeList(TInt aDrive,TInt aIndex);
|
|
125 |
|
|
126 |
//Removes all filters from iFilterList
|
|
127 |
TInt RemoveFilters();
|
|
128 |
|
|
129 |
//Add single filter to this request
|
|
130 |
TInt AddFilterL(CFsNotificationPathFilter* aFilter, TUint aMask);
|
|
131 |
|
|
132 |
//Sets filter as active/inactive
|
|
133 |
void SetActive(TNotifyRequestStatus aValue);
|
|
134 |
|
|
135 |
/**
|
|
136 |
*Get the status of this request.
|
|
137 |
*@See TNotifyRequestStatus
|
|
138 |
*/
|
|
139 |
TNotifyRequestStatus ActiveStatus();
|
|
140 |
|
|
141 |
/*
|
|
142 |
* Completes and frees notification request
|
|
143 |
*
|
|
144 |
* @param aIsCancel is used to determine whether
|
|
145 |
* to write back to the client or not when aReason != KErrNone.
|
|
146 |
*
|
|
147 |
* In the case of closing the subsession you shouldn't write back to the client.
|
|
148 |
*/
|
|
149 |
void CompleteClientRequest(TInt aReason,TBool aIsCancel=EFalse);
|
|
150 |
|
|
151 |
//RfsNotify::RequestNotifications has been called
|
|
152 |
TInt SetClientMessage(const RMessage2& aClientMsg);
|
|
153 |
|
|
154 |
/*
|
|
155 |
* Called from FsNotificationManager::HandleChange(),
|
|
156 |
* this function packages the data in to a CFsNotificationBlock in preperation for
|
|
157 |
* notification of this operation to the client.
|
|
158 |
*
|
|
159 |
* Calling of this function means that we are notifying about this operation. (all checks passed)
|
|
160 |
*
|
|
161 |
* aRequest can be NULL when the request doesn't come from the file server
|
|
162 |
* (such as when a media card is removed)
|
|
163 |
*/
|
|
164 |
TInt NotifyChange(CFsClientMessageRequest* aRequest, const TDesC& aName, TFsNotification::TFsNotificationType aNotificationType, CFsNotificationBlock& aBlock);
|
|
165 |
|
|
166 |
/*
|
|
167 |
* This function performs the IPC to the client's buffer.
|
|
168 |
*/
|
|
169 |
TInt SynchroniseBuffer(CFsNotificationBlock& aBlock,TInt aServerTail, TInt aNotificationSize);
|
|
170 |
|
|
171 |
//Closing this notification
|
|
172 |
void CloseNotification();
|
|
173 |
|
|
174 |
//Simple getter
|
|
175 |
TInt ClientMsgHandle();
|
|
176 |
|
|
177 |
private:
|
|
178 |
CFsNotifyRequest();
|
|
179 |
void ConstructL();
|
|
180 |
|
|
181 |
//Check whether there is room for a new notification in the client's buffer
|
|
182 |
TBool ValidateNotification(TInt aNotificationSize, TInt& aServerTail);
|
|
183 |
|
|
184 |
/*
|
|
185 |
* The iTailSemaphore is used so that many CFsNotificationBlocks can
|
|
186 |
* be processed concurrently.
|
|
187 |
* This lock ensures that the iServerTail is safe.
|
|
188 |
*/
|
|
189 |
//ToDo: This should be a ReadWriteLock
|
|
190 |
RFastLock iTailSemaphore;
|
|
191 |
|
|
192 |
/*
|
|
193 |
* The iClientSyncLock is a Read/Write style lock whereby it is
|
|
194 |
* set up with the value of KNotificationPoolSize.
|
|
195 |
* When a block is allocated it calls wait on this lock.
|
|
196 |
*
|
|
197 |
* This lock is to ensure that all of the currently processing blocks are
|
|
198 |
* written before the client is updated.
|
|
199 |
*
|
|
200 |
* i.e. if two blocks are being processed concurrently and the second
|
|
201 |
* block is written we need to wait until the first one is also written
|
|
202 |
* before the client receives the updated tail.
|
|
203 |
*/
|
|
204 |
//ToDo: This should be a ReadWriteLock
|
|
205 |
RFastLock iClientSyncLock;
|
|
206 |
|
|
207 |
|
|
208 |
/*
|
|
209 |
* HashMap<DriveNumber, TFsNotificationTypeDriveArray>
|
|
210 |
* HashMap<DriveNumber, RArray<TFsNotificationTypeArray>>
|
|
211 |
* HashMap<DriveNumber, RArray<RArray<TFsNotificationTypeFilter>>>
|
|
212 |
*
|
|
213 |
* Each value of iDrivesTypesFiltersMap is of type TFsNotificationTypeDriveArray
|
|
214 |
* associated with a particular drive.
|
|
215 |
*
|
|
216 |
* Each index of the TFsNotificationTypeDriveArray is a TFsNotificationTypeArray
|
|
217 |
*/
|
|
218 |
RHashMap<TInt,TFsNotificationTypeDriveArray> iDrivesTypesFiltersMap;
|
|
219 |
|
|
220 |
/*
|
|
221 |
* The iPathFilterList is an RPointerArray of CFsNotificationPathFilters.
|
|
222 |
*
|
|
223 |
* These are normally only accessed via a TFsNotificationTypeFilter (via iDrivesTypesFiltersMap),
|
|
224 |
* not via this array directly.
|
|
225 |
*/
|
|
226 |
RPointerArray<CFsNotificationPathFilter> iPathFilterList;
|
|
227 |
|
|
228 |
RMessage2 iBufferMsg; //To update buffer
|
|
229 |
RMessage2 iClientMsg; //client notification request
|
|
230 |
|
|
231 |
CSessionFs* iSession; //Session associated with this request (TFsSessionDisconnect::DoRequestL)
|
|
232 |
|
|
233 |
TNotifyRequestStatus iNotifyRequestStatus; //Current status of this request
|
|
234 |
|
|
235 |
//The following 3 variables must be aligned when modified.
|
|
236 |
TInt iClientHead; //Offset where the client should start reading from.
|
|
237 |
//If the server writes past this offset we must overflow the client.
|
|
238 |
|
|
239 |
TInt iClientTail; //The end of the client's accessible range.
|
|
240 |
|
|
241 |
TInt iServerTail; //The end of the server's accessible range.
|
|
242 |
//Overflow occurs if iServerTail becomes more than iClientHead.
|
|
243 |
|
|
244 |
TInt iClientBufferSize; //Buffer size is word-aligned.
|
|
245 |
|
|
246 |
friend class TFsNotificationBuffer; //For access to iClientBufferSize and iBufferMsg
|
|
247 |
friend class TFsNotificationRequest;//For access to iClientBufferSize
|
|
248 |
friend class FsNotificationManager; //For access to iSession
|
|
249 |
friend class TFsNotificationOpen; //For access to iSession
|
|
250 |
friend class TFsNotificationRemove; //For access to iDrivesTypesFiltersMap
|
|
251 |
};
|
|
252 |
|
|
253 |
/**
|
|
254 |
* A CFsNotificationBlock is a chunk of memory which is used to represent a notification
|
|
255 |
* such that a single IPC can be performed from server to client.
|
|
256 |
*
|
|
257 |
* CFsNotificationBlocks are stored in a CFsPool<CFsNotificationBlock>.
|
|
258 |
*
|
|
259 |
*@internalTechnology
|
|
260 |
*/
|
|
261 |
class CFsNotificationBlock
|
|
262 |
{
|
|
263 |
public:
|
|
264 |
static CFsNotificationBlock* New();
|
|
265 |
~CFsNotificationBlock();
|
|
266 |
TAny* Data();
|
|
267 |
private:
|
|
268 |
CFsNotificationBlock();
|
|
269 |
TText8 iData[KMinNotificationBufferSize];
|
|
270 |
};
|
|
271 |
|
|
272 |
/**
|
|
273 |
* Helper class to get certain attributes from or about a particular operation to used in a notification
|
|
274 |
*
|
|
275 |
* @internalTechnology
|
|
276 |
*/
|
|
277 |
class FsNotificationHelper
|
|
278 |
{
|
|
279 |
public:
|
|
280 |
static void NotificationType(TInt aFunction,TFsNotification::TFsNotificationType& aNotificationType);
|
|
281 |
static void PathName(CFsClientMessageRequest& aRequest, TDes& aName);
|
|
282 |
static void NewPathName(CFsClientMessageRequest& aRequest, TPtrC& aName);
|
|
283 |
static TInt NotificationSize(CFsClientMessageRequest& aRequest, TFsNotification::TFsNotificationType aNotificationType, const TDesC& aName);
|
|
284 |
static TInt TypeToIndex(TFsNotification::TFsNotificationType aType);
|
|
285 |
static TFsNotification::TFsNotificationType NotificationType(TInt& aIndex);
|
|
286 |
static TInt DriveNumber(const TPtrC& aPath);
|
|
287 |
static void Attributes(CFsClientMessageRequest& aRequest, TUint& aSet, TUint& aClear);
|
|
288 |
};
|
|
289 |
|
|
290 |
/**
|
|
291 |
* The FsNotificationManager is a static object
|
|
292 |
*
|
|
293 |
*@internalTechnology
|
|
294 |
*/
|
|
295 |
class FsNotificationManager
|
|
296 |
{
|
|
297 |
public:
|
|
298 |
//New notification request from client
|
|
299 |
static void AddNotificationRequestL(CFsNotifyRequest* aNotificationRequest);
|
|
300 |
|
|
301 |
//Notification request cancel
|
|
302 |
static void RemoveNotificationRequest(CFsNotifyRequest* aNotificationRequest);
|
|
303 |
//Notification request cancel (session closed)
|
|
304 |
static void RemoveNotificationRequest(CSessionFs* aSession);
|
|
305 |
|
|
306 |
/* A change has occurred represented by this request.
|
|
307 |
* Work out which CFsNotifyRequests are interested
|
|
308 |
* (if any) and call CFsNotifyRequest::NotifyChange.
|
|
309 |
*/
|
|
310 |
static void HandleChange(CFsClientMessageRequest& aRequest);
|
|
311 |
|
|
312 |
/* A change has occurred represented by this request.
|
|
313 |
* Work out which CFsNotifyRequests are interested
|
|
314 |
* (if any) and call CFsNotifyRequest::NotifyChange.
|
|
315 |
*
|
|
316 |
* This override is used directly when we want to force a particular notification type
|
|
317 |
*/
|
|
318 |
static void HandleChange(CFsClientMessageRequest& aRequest, TFsNotification::TFsNotificationType aType);
|
|
319 |
|
|
320 |
/*
|
|
321 |
* This override is used directly when we want to specify the current operation's name (src) and notification type.
|
|
322 |
*
|
|
323 |
* aRequest can be NULL when the request doesn't come from the file server
|
|
324 |
* such as when a media card is removed, see LocalDrives::CompleteDriveNotifications
|
|
325 |
*
|
|
326 |
* @See LocalDrives::CompleteDriveNotifications(TInt aDrive)
|
|
327 |
*/
|
|
328 |
static void HandleChange(CFsClientMessageRequest* aRequest, const TDesC& aOperationName, TFsNotification::TFsNotificationType aType);
|
|
329 |
|
|
330 |
//Initialise iNotifyRequests and iStaticNotification
|
|
331 |
static void OpenL();
|
|
332 |
static TBool IsInitialised();
|
|
333 |
|
|
334 |
/*
|
|
335 |
* On CFsNotifyRequest closing, Close is called if this is the last request being removed.
|
|
336 |
* This removes all of the managers private data.
|
|
337 |
*/
|
|
338 |
static void Close();
|
|
339 |
|
|
340 |
/*
|
|
341 |
* Calls SetFilterRegister for every valid notification set in aMask.
|
|
342 |
*/
|
|
343 |
static void SetFilterRegisterMask(TUint aMask,TBool aAdd);
|
|
344 |
|
|
345 |
/*
|
|
346 |
* Adds or Removes to the count of filters set up for a particular type
|
|
347 |
* This is a global count such that if there are no fiters for a particular type
|
|
348 |
* HandleChange doesn't need to do any iteration for that type.
|
|
349 |
*/
|
|
350 |
static void SetFilterRegister(TUint aFilter, TBool aAdd, TInt aCount = 1);
|
|
351 |
/*
|
|
352 |
* Get the number of registers filters set up on a particular type.
|
|
353 |
* @param aIndex the TFsNotificationType's index as determined from FsNotificationHelper::TypeToIndex
|
|
354 |
*/
|
|
355 |
static TInt& FilterRegister(TInt aIndex);
|
|
356 |
|
|
357 |
/*
|
|
358 |
* Returns the number of CFsNotifyRequests set up
|
|
359 |
*/
|
|
360 |
static TInt Count();
|
|
361 |
|
|
362 |
/*
|
|
363 |
* Lock the iChainLock (currently not a ReadWriteLock)
|
|
364 |
*/
|
|
365 |
static void Lock();
|
|
366 |
|
|
367 |
/*
|
|
368 |
* Unlock iChainLock
|
|
369 |
*/
|
|
370 |
static void Unlock();
|
|
371 |
|
|
372 |
private:
|
|
373 |
|
|
374 |
/*
|
|
375 |
* @internalTechnology
|
|
376 |
* Used by DoMatchFilter and DoHandleChange to control the flow of
|
|
377 |
* loop execution.
|
|
378 |
*/
|
|
379 |
enum TFsNotificationFilterMatch
|
|
380 |
{
|
|
381 |
EDifferent = 0x00, //Operation and Filters do not match.
|
|
382 |
EMatch = 0x01, //Operation and Filters do match.
|
|
383 |
EContinue = 0x02 //Data caged directory - Do not notify.
|
|
384 |
};
|
|
385 |
|
|
386 |
/*
|
|
387 |
* Checks whether aOperation matches the filter name and/or path set in aFilter.
|
|
388 |
*/
|
|
389 |
static TFsNotificationFilterMatch DoMatchFilter(CFsClientMessageRequest* aRequest, const TDesC& aOperationName,CFsNotificationPathFilter& aFilter);
|
|
390 |
|
|
391 |
/*
|
|
392 |
* Iterates filters for a particular drive.
|
|
393 |
* Called from HandleChange
|
|
394 |
*/
|
|
395 |
static void DoHandleChange(TFsNotificationTypeArray* aFilterTypeArray, TInt& aSeenFilter, CFsClientMessageRequest* aRequest, CFsNotifyRequest* aNotifyRequest, const TDesC& aOperationName, TFsNotification::TFsNotificationType& aType);
|
|
396 |
|
|
397 |
/*
|
|
398 |
* Stores the CFsNotifyRequests
|
|
399 |
*/
|
|
400 |
static CFsObjectCon* iNotifyRequests;
|
|
401 |
|
|
402 |
//As we are doing notifications 'in-place' which is multi-threaded
|
|
403 |
//we need to have locking to protect iNotifyRequests.
|
|
404 |
//ToDo: ReadWriteLock
|
|
405 |
static RFastLock iChainLock;
|
|
406 |
|
|
407 |
/*
|
|
408 |
* Global register per filter type.
|
|
409 |
* Keeps a count of the number of filters set up for a particular type
|
|
410 |
* (NB: EMediaChange is reported regardless of filters set)
|
|
411 |
*/
|
|
412 |
static TInt iFilterRegister[KNumRegisterableFilters];
|
|
413 |
|
|
414 |
/*
|
|
415 |
* This is a pool of blocks which are server-side versions of TFsNotification.
|
|
416 |
* They are used so that we can have a single IPC from server to client.
|
|
417 |
*
|
|
418 |
* it will also be used for coalescing changes.
|
|
419 |
*/
|
|
420 |
static CFsPool<CFsNotificationBlock>* iPool;
|
|
421 |
|
|
422 |
friend class CFsNotifyRequest;
|
|
423 |
friend class RequestAllocator;
|
|
424 |
friend class TFsNotificationSubClose;
|
|
425 |
};
|
|
426 |
|
|
427 |
|
|
428 |
#endif /* SF_NOTIFIER_H */
|
|
429 |
|
|
430 |
|