|
1 // Copyright (c) 2004-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 "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 // Reserving/Accessing/Releasing drive space - CDriveSpace, RDriveSpaceCol, CDbsSessDriveSpace |
|
15 // classes implementations |
|
16 // |
|
17 // |
|
18 |
|
19 #include "U32STD.H" |
|
20 #include "Sd_DriveSpace.h" |
|
21 |
|
22 /** |
|
23 That's the amount of the disk space, which will be reserved at the momemnt of creation of |
|
24 each CDriveSpace object. |
|
25 It should be enough for the most of the "delete" transactions, used by the applications. |
|
26 @internalComponent |
|
27 */ |
|
28 const TInt KReservedDiskSpace = 64 * 1024; |
|
29 |
|
30 ///////////////////////////////////////////////////////////////////////////////////////////// |
|
31 //CDriveSpace class |
|
32 |
|
33 /** |
|
34 Grants access to the already reserved drive space. The method uses RFs::GetReserveAccess() |
|
35 for that. RFs::GetReserveAccess() will be called only once, when iGrantAccessRefCnt is 0 - |
|
36 this is a shared file session instance. |
|
37 @leave RFs::GetReserveAccess() return values |
|
38 @see RFs::GetReserveAccess() |
|
39 @panic In debug mode there will be a panic with the line number as an error code if (iGrantAccessRefCnt < 0) |
|
40 */ |
|
41 void CDriveSpace::GrantAccessL() |
|
42 { |
|
43 __ASSERT(iGrantAccessRefCnt >= 0); |
|
44 //Grant the access only once, there is only one RFs session instance. |
|
45 if(iGrantAccessRefCnt == 0) |
|
46 { |
|
47 __LEAVE_IF_ERROR(iFs.GetReserveAccess(static_cast <TInt> (iDrive))); |
|
48 } |
|
49 ++iGrantAccessRefCnt; |
|
50 } |
|
51 |
|
52 /** |
|
53 Revokes access to the reserved drive space. |
|
54 The method calls RFs::ReleaseReserveAccess() only when iGrantAccessRefCnt value reaches 0. |
|
55 @see RFs::ReleaseReserveAccess() |
|
56 @panic In debug mode there will be a panic with the line number as an error code if (iGrantAccessRefCnt <= 0) |
|
57 */ |
|
58 void CDriveSpace::ReleaseAccess() |
|
59 { |
|
60 __ASSERT(iGrantAccessRefCnt > 0); |
|
61 if(iGrantAccessRefCnt == 0) |
|
62 { |
|
63 return; |
|
64 } |
|
65 if(--iGrantAccessRefCnt == 0) |
|
66 { |
|
67 //I can't see any reason to bother the caller with errors, when the access to the |
|
68 //reserved space is revoked. |
|
69 (void)iFs.ReleaseReserveAccess(static_cast <TInt> (iDrive)); |
|
70 } |
|
71 } |
|
72 |
|
73 /** |
|
74 Standard phase-one factory method for creation of CDriveSpace objects. |
|
75 @param aFs File session instance |
|
76 @param aDrive Drive number |
|
77 @return A pointer to the created CDriveSpace object. |
|
78 @leave KErrNoMemory Out of memory |
|
79 @leave RFs::ReserveDriveSpace() return values |
|
80 @see RFs::ReserveDriveSpace() |
|
81 */ |
|
82 CDriveSpace* CDriveSpace::NewLC(RFs& aFs, TDriveNumber aDrive) |
|
83 { |
|
84 CDriveSpace* self = new (ELeave) CDriveSpace(aFs, aDrive); |
|
85 CleanupStack::PushL(self); |
|
86 self->ConstructL(); |
|
87 return self; |
|
88 } |
|
89 |
|
90 /** |
|
91 @param aFs File session instance |
|
92 @param aDrive Drive number |
|
93 @panic In debug mode there will be a panic with the line number as an error code if |
|
94 (iDrive value is not between EDriveA and EDriveZ) |
|
95 */ |
|
96 CDriveSpace::CDriveSpace(RFs& aFs, TDriveNumber aDrive) : |
|
97 iFs(aFs), |
|
98 iDrive(aDrive) |
|
99 { |
|
100 __ASSERT(iDrive >= EDriveA && iDrive <= EDriveZ); |
|
101 } |
|
102 |
|
103 /** |
|
104 Frees the reserved disk space. |
|
105 @panic In debug mode there will be a panic with the line number as an error code if |
|
106 (iGrantAccessRefCnt != 0) |
|
107 */ |
|
108 CDriveSpace::~CDriveSpace() |
|
109 { |
|
110 __ASSERT(iGrantAccessRefCnt == 0); |
|
111 if(iGrantAccessRefCnt > 0) |
|
112 { |
|
113 (void)iFs.ReleaseReserveAccess(static_cast <TInt> (iDrive)); |
|
114 } |
|
115 (void)iFs.ReserveDriveSpace(static_cast <TInt> (iDrive), 0); |
|
116 } |
|
117 |
|
118 /** |
|
119 Standard phase-two construction method for creation of CDriveSpace objects. |
|
120 It will reserve a predefined amount of a disk space, enough for the most of the |
|
121 "delete" transactions, used by the applications. |
|
122 @leave RFs::ReserveDriveSpace() return values |
|
123 @see RFs::ReserveDriveSpace() |
|
124 */ |
|
125 void CDriveSpace::ConstructL() |
|
126 { |
|
127 __LEAVE_IF_ERROR(iFs.ReserveDriveSpace(static_cast <TInt> (iDrive), KReservedDiskSpace)); |
|
128 } |
|
129 |
|
130 ///////////////////////////////////////////////////////////////////////////////////////////// |
|
131 //RDriveSpaceCol class |
|
132 |
|
133 /** |
|
134 @param aFs File session instance |
|
135 */ |
|
136 RDriveSpaceCol::RDriveSpaceCol(RFs& aFs) : |
|
137 iFs(aFs) |
|
138 { |
|
139 } |
|
140 |
|
141 /** |
|
142 The method releases all the resources used by RDriveSpaceCol object, including and |
|
143 reserved drive spaces on all drives in the collection. |
|
144 */ |
|
145 void RDriveSpaceCol::Close() |
|
146 { |
|
147 //Forced release of the reserved space |
|
148 for(TInt i=iDriveSpaceCol.Count()-1;i>=0;--i) |
|
149 { |
|
150 delete iDriveSpaceCol[i]; |
|
151 } |
|
152 iDriveSpaceCol.Close(); |
|
153 } |
|
154 |
|
155 /** |
|
156 The method returns a pointer to the CDriveSpace object, which handles all drive space |
|
157 requests, related to a particular drive. |
|
158 @param aDrive Drive number. |
|
159 @return A pointer to the CDriveSpace object, which handles drive space reservation requests |
|
160 for aDriveNo drive. If there is no such object, the method returns NULL. |
|
161 */ |
|
162 CDriveSpace* RDriveSpaceCol::Find(TDriveNumber aDrive) |
|
163 { |
|
164 for(TInt index=iDriveSpaceCol.Count()-1;index>=0;--index) |
|
165 { |
|
166 if(iDriveSpaceCol[index]->iDrive == aDrive) |
|
167 { |
|
168 return iDriveSpaceCol[index]; |
|
169 } |
|
170 } |
|
171 return NULL; |
|
172 } |
|
173 |
|
174 /** |
|
175 The method creates a new CDriveSpace object, adds it to the collection and |
|
176 returns a pointer to it. |
|
177 @param aDrive Drive number. |
|
178 @return A pointer to the created CDriveSpace object, which handles drive space |
|
179 reservation requests for aDriveNo drive. |
|
180 @leave System-wide error codes, including KErrNoMemory. |
|
181 @panic In debug mode there will be a panic with the line number as an error code if |
|
182 a CDriveSpace object already exists for aDrive. |
|
183 */ |
|
184 CDriveSpace* RDriveSpaceCol::CreateAddL(TDriveNumber aDrive) |
|
185 { |
|
186 __ASSERT(!Find(aDrive)); |
|
187 CDriveSpace* drvSpace = CDriveSpace::NewLC(iFs, aDrive); |
|
188 __LEAVE_IF_ERROR(iDriveSpaceCol.Append(drvSpace)); |
|
189 CleanupStack::Pop(drvSpace); |
|
190 return drvSpace; |
|
191 } |
|
192 |
|
193 ///////////////////////////////////////////////////////////////////////////////////////////// |
|
194 //TDriveSpaceRq class |
|
195 |
|
196 /** |
|
197 @param aDriveSpace A reference to the CDriveSpace object, which handles the reservation requests |
|
198 for a particular drive. |
|
199 */ |
|
200 CDbsSessDriveSpace::TDriveSpaceRq::TDriveSpaceRq(CDriveSpace& aDriveSpace) : |
|
201 iDriveSpace(aDriveSpace), |
|
202 iReserved(0), |
|
203 iAccessGranted(0) |
|
204 { |
|
205 } |
|
206 |
|
207 ///////////////////////////////////////////////////////////////////////////////////////////// |
|
208 //CDbsSessDriveSpace class |
|
209 |
|
210 /** |
|
211 Standard phase-one factory method for creation of CDbsSessDriveSpace objects. |
|
212 @param aDriveSpaceCol A reference to the RDriveSpaceCol collection - there should be only one |
|
213 per DBMS server. |
|
214 @return A pointer to the created CDbsSessDriveSpace object. |
|
215 @leave KErrNoMemory Out of memory |
|
216 */ |
|
217 CDbsSessDriveSpace* CDbsSessDriveSpace::NewL(RDriveSpaceCol& aDriveSpaceCol) |
|
218 { |
|
219 CDbsSessDriveSpace* self = new (ELeave) CDbsSessDriveSpace(aDriveSpaceCol); |
|
220 return self; |
|
221 } |
|
222 |
|
223 /** |
|
224 @param aDriveSpaceCol A reference to the RDriveSpaceCol collection - there should be only one |
|
225 per DBMS server. |
|
226 */ |
|
227 CDbsSessDriveSpace::CDbsSessDriveSpace(RDriveSpaceCol& aDriveSpaceCol) : |
|
228 iDriveSpaceCol(aDriveSpaceCol) |
|
229 { |
|
230 } |
|
231 |
|
232 /** |
|
233 Releases the allocated resources, which means the CDriveSpace::ReleaseAccess() |
|
234 will be called if TDriveSpaceRq::iAccessGranted for the related drive is set. |
|
235 */ |
|
236 CDbsSessDriveSpace::~CDbsSessDriveSpace() |
|
237 { |
|
238 for(TInt i=iDriveSpaceRqCol.Count()-1;i>=0;--i) |
|
239 { |
|
240 TDriveSpaceRq& rq = iDriveSpaceRqCol[i]; |
|
241 if(rq.iAccessGranted) |
|
242 { |
|
243 rq.iDriveSpace.ReleaseAccess(); |
|
244 } |
|
245 //That's all! |
|
246 //rq.iDriveSpace object shall not be destroyed or the reserved disk space - freed! |
|
247 //It will be freed at the DBMS server shutdown. |
|
248 }//end of: for(TInt i=iDriveSpaceRqCol.Count()-1;i>=0;--i) |
|
249 iDriveSpaceRqCol.Close(); |
|
250 } |
|
251 |
|
252 /** |
|
253 The method reserves the requested amount of disk space. |
|
254 Because it is a shared file session between all DBMS sessions, a predefined amount of |
|
255 disk space per drive will be reserved at the moment of the first request made by some of |
|
256 the DBMS sessions. All the requests after the first (for a particular disk drive) will |
|
257 be completed successfully without actually reserving a disk space. |
|
258 Only the state of the related TDriveSpaceRq object will be updated to make it possible to |
|
259 control reservation/freeing requests. |
|
260 @param aDrive Drive number to reserve space on. |
|
261 @leave KErrNoMemory Out of memory |
|
262 @leave KErrInUse This DBMS session has already reserved a disk space. |
|
263 @leave RFs::ReserveDriveSpace() return values |
|
264 @see RFs::ReserveDriveSpace() |
|
265 */ |
|
266 void CDbsSessDriveSpace::ReserveL(TDriveNumber aDrive) |
|
267 { |
|
268 TDriveSpaceRq& rq = GetL(aDrive); |
|
269 if(rq.iReserved || rq.iAccessGranted) |
|
270 { |
|
271 //This DBMS session already reserved a disk space (or even has an access to it). |
|
272 //The DBMS session has to free it and then can re-reserve it again. |
|
273 __LEAVE(KErrInUse); |
|
274 } |
|
275 rq.iReserved = 1; //CDriveSpace object reserves a predefined amount of disk space at |
|
276 //at the moment of its creation, so just set rq.iReserved to non-zero, |
|
277 //indicating that this session has reserved a disk space. |
|
278 } |
|
279 |
|
280 /** |
|
281 The method frees the reserved by the DBMS session disk space. |
|
282 The actual implementation won't free the reserved disk space. This will happen at the moment of |
|
283 the destruction of the related CDriveSpace object for aDrive drive. |
|
284 The method just updates the state of the related TDriveSpaceRq object to make it possible to |
|
285 control reservation/freeing requests. |
|
286 @param aDrive Drive number, which reserved space has to be freed. |
|
287 @panic In debug mode there will be a panic with the line number as an error code if |
|
288 there is no TDriveSpaceRq object for aDrive. |
|
289 @panic In debug mode there will be a panic with the line number as an error code if |
|
290 the reserved disk space is granted but not released. |
|
291 @panic In debug mode there will be a panic with the line number as an error code if |
|
292 there is no reserved disk space for aDrive. |
|
293 */ |
|
294 void CDbsSessDriveSpace::Free(TDriveNumber aDrive) |
|
295 { |
|
296 TDriveSpaceRq* rq = Find(aDrive); |
|
297 __ASSERT(rq);//Probably an attempt to free non-reserved disk space. |
|
298 __ASSERT(!rq->iAccessGranted);//An attempt to free reserved and granted disk space. |
|
299 __ASSERT(rq->iReserved);//Probably an attempt to free non-reserved disk space. |
|
300 if(rq) |
|
301 { |
|
302 rq->iReserved = 0;//Set it to 0, without actually freeing the reserved disk space. |
|
303 //It is shared between all DBMS sessions. |
|
304 } |
|
305 } |
|
306 |
|
307 /** |
|
308 Gets an access to the reserved drive space. |
|
309 @param aDriveNo Drive number with a reserved disk space, an access to which is requested |
|
310 @leave KErrArgument There is no reserved disk space on aDrive. |
|
311 @leave KErrInUse An access to the reserved space has already been granted. |
|
312 @leave RFs::GetReserveAccess() return values |
|
313 @see RFs::GetReserveAccess() |
|
314 */ |
|
315 void CDbsSessDriveSpace::GrantAccessL(TDriveNumber aDrive) |
|
316 { |
|
317 TDriveSpaceRq* rq = Find(aDrive); |
|
318 if(!rq) |
|
319 {//Probably an attempt to get an access to a non-reserved disk space. |
|
320 __LEAVE(KErrArgument); |
|
321 } |
|
322 if(!rq->iReserved) |
|
323 {//Probably an attempt to get an access to a non-reserved disk space. |
|
324 __LEAVE(KErrArgument); |
|
325 } |
|
326 if(rq->iAccessGranted) |
|
327 {//Probably an attempt to get an access twice to the reserved disk space. |
|
328 __LEAVE(KErrInUse); |
|
329 } |
|
330 rq->iDriveSpace.GrantAccessL(); |
|
331 rq->iAccessGranted = 1; |
|
332 } |
|
333 |
|
334 /** |
|
335 Releases the access to the reserved drive space. |
|
336 @param aDriveNo Drive number with a reserved disk space, the access to which has to be released. |
|
337 @panic In debug mode there will be a panic with the line number as an error code if |
|
338 there is no TDriveSpaceRq object for aDrive. |
|
339 @panic In debug mode there will be a panic with the line number as an error code if |
|
340 there is no reserved disk space for aDrive. |
|
341 @panic In debug mode there will be a panic with the line number as an error code if |
|
342 there is no granted access to the reserved disk space. |
|
343 */ |
|
344 void CDbsSessDriveSpace::ReleaseAccess(TDriveNumber aDrive) |
|
345 { |
|
346 TDriveSpaceRq* rq = Find(aDrive); |
|
347 __ASSERT(rq);//Probably an attempt to release the access to a non-reserved disk space. |
|
348 if(rq) |
|
349 { |
|
350 __ASSERT(rq->iReserved);//Probably an attempt to release the access to a non-reserved disk space. |
|
351 __ASSERT(rq->iAccessGranted);//Probably an attempt to grant an access to the reserved disk spave twice. |
|
352 if(rq->iReserved && rq->iAccessGranted) |
|
353 { |
|
354 rq->iDriveSpace.ReleaseAccess(); |
|
355 rq->iAccessGranted = 0; |
|
356 } |
|
357 } |
|
358 } |
|
359 |
|
360 /** |
|
361 The method searches iDriveSpaceRqCol collection for TDriveSpaceRq object, which drive number |
|
362 is the same as aDrive parameter. |
|
363 @param aDrive Drive number |
|
364 @return A pointer to the TDriveSpaceRq object, which has the same drive number |
|
365 NULL, if there is no such opject. |
|
366 */ |
|
367 CDbsSessDriveSpace::TDriveSpaceRq* CDbsSessDriveSpace::Find(TDriveNumber aDrive) |
|
368 { |
|
369 for(TInt index=iDriveSpaceRqCol.Count()-1;index>=0;--index) |
|
370 { |
|
371 if(iDriveSpaceRqCol[index].iDriveSpace.Drive() == aDrive) |
|
372 { |
|
373 return &iDriveSpaceRqCol[index]; |
|
374 } |
|
375 } |
|
376 return NULL; |
|
377 } |
|
378 |
|
379 /** |
|
380 The method creates a new TDriveSpaceRq object with aDrive as a drive number and adds it |
|
381 to iDriveSpaceRqCol collection. |
|
382 @param aDrive Drive number |
|
383 @return A reference to the created TDriveSpaceRq object |
|
384 @leave System-wide error codes, including KErrNoMemory. |
|
385 @panic In debug mode there will be a panic with the line number as an error code if |
|
386 there is an existing TDriveSpaceRq object for aDrive. |
|
387 */ |
|
388 CDbsSessDriveSpace::TDriveSpaceRq& CDbsSessDriveSpace::CreateAddL(TDriveNumber aDrive) |
|
389 { |
|
390 __ASSERT(!Find(aDrive)); |
|
391 //Check iDriveSpaceCol collection if there is a CDriveSpace object, which was already |
|
392 //created for aDrive. |
|
393 CDriveSpace* drvSpace = iDriveSpaceCol.Find(aDrive); |
|
394 if(!drvSpace) |
|
395 {//There is no CDriveSpace object for aDrive. It has to be created. |
|
396 drvSpace = iDriveSpaceCol.CreateAddL(aDrive); |
|
397 } |
|
398 __ASSERT(drvSpace); |
|
399 //Now we have the related CDriveSpace object for aDrive. |
|
400 //Create new TDriveSpaceRq object and add it to iDriveSpaceRqCol collection. |
|
401 __LEAVE_IF_ERROR(iDriveSpaceRqCol.Append(TDriveSpaceRq(*drvSpace))); |
|
402 //If Append() call fails, then we have CDriveSpace object created but not deleted. |
|
403 //It is not a problem, because CDriveSpace object was added to iDriveSpaceCol and will |
|
404 //be destroyed when iDriveSpaceCol is destroyed. |
|
405 return iDriveSpaceRqCol[iDriveSpaceRqCol.Count() - 1]; |
|
406 } |
|
407 |
|
408 /** |
|
409 This method combines the functionality of CDbsSessDriveSpace::Find() and |
|
410 CDbsSessDriveSpace::CreateAddL() methods. |
|
411 It will search for a TDriveSpaceRq object with the same drive number as aDrive. |
|
412 If such object doesn not exist, it will be created, added to iDriveSpaceRqCol and a reference |
|
413 to it - returned. |
|
414 @param aDrive Drive number |
|
415 @return A reference to the TDriveSpaceRq object, responsible for aDrive drive. |
|
416 @leave System-wide error codes, including KErrNoMemory. |
|
417 @see CDbsSessDriveSpace::Find() |
|
418 @see CDbsSessDriveSpace::CreateAddL() |
|
419 */ |
|
420 CDbsSessDriveSpace::TDriveSpaceRq& CDbsSessDriveSpace::GetL(TDriveNumber aDrive) |
|
421 { |
|
422 TDriveSpaceRq* rq = Find(aDrive); |
|
423 return rq ? *rq : CreateAddL(aDrive); |
|
424 } |