|
1 // Copyright (c) 1996-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 // Common CFatMountCB code for both EFAT.FSY and EFAT32.fsy |
|
15 // |
|
16 // |
|
17 |
|
18 /** |
|
19 @file |
|
20 @internalTechnology |
|
21 */ |
|
22 |
|
23 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|
24 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|
25 //!! |
|
26 //!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it |
|
27 //!! |
|
28 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|
29 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|
30 |
|
31 |
|
32 #include "sl_std.h" |
|
33 #include "sl_cache.h" |
|
34 #include "sl_leafdir_cache.h" |
|
35 #include "sl_dir_cache.h" |
|
36 #include "sl_scandrv.h" |
|
37 #include <hal.h> |
|
38 |
|
39 TShortName DoGenerateShortNameL(const TDesC& aLongName,TInt& aNum,TBool aUseTildeSelectively); |
|
40 |
|
41 static void MarkClusterVisited(RBitVector& aFatBitVec, TUint32 aCluster); |
|
42 static TBool IsClusterVisited(const RBitVector& aFatBitVec, TUint32 aCluster); |
|
43 static TInt NextUnvisitedCluster(const RBitVector& aFatBitVec, TUint32 aCluster); |
|
44 |
|
45 //----------------------------------------------------------------------------------------- |
|
46 |
|
47 TFatVolParam::TFatVolParam() |
|
48 { |
|
49 Mem::FillZ(this, sizeof(TFatVolParam)); |
|
50 } |
|
51 |
|
52 /** |
|
53 populate the object with the values from the boot sector. |
|
54 @param aBootSector a reference to the valid boots sector |
|
55 */ |
|
56 void TFatVolParam::Populate(const TFatBootSector& aBootSector) |
|
57 { |
|
58 ASSERT(aBootSector.IsValid()); |
|
59 |
|
60 iSectorsPerCluster = aBootSector.SectorsPerCluster(); |
|
61 iSectorSizeLog2 = Log2(aBootSector.BytesPerSector()); |
|
62 iClusterSizeLog2 = iSectorSizeLog2+Log2(iSectorsPerCluster); |
|
63 iFirstFatSector = aBootSector.FirstFatSector(); |
|
64 iNumberOfFats = aBootSector.NumberOfFats(); |
|
65 iFatSizeInBytes = aBootSector.TotalFatSectors()*aBootSector.BytesPerSector(); |
|
66 iTotalSectors = aBootSector.VolumeTotalSectorNumber(); |
|
67 iRootClusterNum = aBootSector.RootClusterNum(); //-- will be 0 for FAT12/16 |
|
68 |
|
69 iRootDirectorySector = aBootSector.RootDirStartSector(); |
|
70 iRootDirEnd = (iRootDirectorySector + aBootSector.RootDirSectors()) << SectorSizeLog2(); //-- doesn't matter for FAT32 |
|
71 |
|
72 //-- get main and backup FSInfo sectors position, these fields will be 0 for FAT12/16 |
|
73 iFSInfoSectorNum = aBootSector.FSInfoSectorNum(); |
|
74 iBkFSInfoSectorNum = (TUint16)(aBootSector.BkBootRecSector()+iFSInfoSectorNum); //-- Bk FSInfo sector must follow the Bk boot sector |
|
75 } |
|
76 |
|
77 TBool TFatVolParam::operator==(const TFatVolParam& aRhs) const |
|
78 { |
|
79 ASSERT(&aRhs != this); |
|
80 if(&aRhs == this) |
|
81 return ETrue; //-- comparing with itself |
|
82 |
|
83 return (Mem::Compare((TUint8*)this, sizeof(TFatVolParam), (TUint8*)&aRhs, sizeof(TFatVolParam)) == 0); |
|
84 } |
|
85 |
|
86 |
|
87 //----------------------------------------------------------------------------------------- |
|
88 |
|
89 |
|
90 CFatMountCB::CFatMountCB() |
|
91 { |
|
92 __PRINT2(_L("CFatMountCB::CFatMountCB() 0x%x, %S"), this, &KThisFsyName); |
|
93 iFatType = EInvalid; |
|
94 iState = ENotMounted; |
|
95 DBG_STATEMENT(iCBRecFlag = 0); //-- debug flag only |
|
96 } |
|
97 |
|
98 CFatMountCB::~CFatMountCB() |
|
99 { |
|
100 __PRINT1(_L("#-CFatMountCB::~CFatMountCB() 0x%x"), this); |
|
101 |
|
102 DoDismount(); |
|
103 |
|
104 delete iNotifier; |
|
105 delete iFatTable; |
|
106 delete iRawDisk; |
|
107 delete iLeafDirCache; |
|
108 |
|
109 } |
|
110 |
|
111 //----------------------------------------------------------------------------------------- |
|
112 |
|
113 CFatMountCB* CFatMountCB::NewL() |
|
114 { |
|
115 CFatMountCB* pSelf = new(ELeave) CFatMountCB; |
|
116 |
|
117 CleanupStack::PushL(pSelf); |
|
118 pSelf->ConstructL(); |
|
119 CleanupStack::Pop(pSelf); |
|
120 |
|
121 return pSelf; |
|
122 } |
|
123 |
|
124 // second-stage constructor |
|
125 void CFatMountCB::ConstructL() |
|
126 { |
|
127 //-- create Notifier |
|
128 iNotifier = CAsyncNotifier::New(); |
|
129 if( !iNotifier ) |
|
130 { |
|
131 Close(); |
|
132 User::Leave(KErrNoMemory); |
|
133 } |
|
134 |
|
135 iNotifier->SetMount(this); |
|
136 } |
|
137 |
|
138 //------------------------------------------------------------------------------------------------------------------- |
|
139 |
|
140 /** |
|
141 Implementation of CMountCB::FileSystemClusterSize(). Returns cluster size of this mount. |
|
142 @return Cluster size value if successful; otherwise KErrNotReady if the mount is not ready. |
|
143 @see CMountCB::FileSystemClusterSize() |
|
144 */ |
|
145 TInt CFatMountCB::ClusterSize() const |
|
146 { |
|
147 if (ClusterSizeLog2()) |
|
148 return (1 << ClusterSizeLog2()); |
|
149 |
|
150 return KErrNotReady; |
|
151 } |
|
152 |
|
153 //------------------------------------------------------------------------------------------------------------------- |
|
154 |
|
155 /** |
|
156 @leave KErrAccessDenied if the mount is read-only |
|
157 */ |
|
158 void CFatMountCB::CheckWritableL() const |
|
159 { |
|
160 if(ReadOnly()) |
|
161 { |
|
162 __PRINT(_L("CFatMountCB is RO!")); |
|
163 User::Leave(KErrAccessDenied); |
|
164 } |
|
165 } |
|
166 |
|
167 /** |
|
168 @leave KErrCorrupt if the mount is in inconsistent state i.e high-level file and directory operations can not be performed |
|
169 */ |
|
170 void CFatMountCB::CheckStateConsistentL() const |
|
171 { |
|
172 if(!ConsistentState()) |
|
173 { |
|
174 __PRINT(_L("CFatMountCB state is inconsistent !")); |
|
175 User::Leave(KErrCorrupt); |
|
176 } |
|
177 } |
|
178 |
|
179 |
|
180 //------------------------------------------------------------------------------------------------------------------- |
|
181 /** |
|
182 Helper Method. Check if the parameters of the volume being remounted are the same as current ones. |
|
183 @return ETrue if volume parameters remained same. |
|
184 */ |
|
185 TBool CFatMountCB::CheckVolumeTheSame() |
|
186 { |
|
187 //-- initialise local drive |
|
188 TInt nRes =InitLocalDrive(); |
|
189 if(nRes != KErrNone) |
|
190 return EFalse; |
|
191 |
|
192 //-- read the boot sector or its backup copy if the main is damaged. It will aslo validate it. |
|
193 TFatBootSector bootSector; |
|
194 nRes = ReadBootSector(bootSector, iRamDrive); |
|
195 if(nRes != KErrNone) |
|
196 return EFalse; |
|
197 |
|
198 //-- 1. check volume Uid |
|
199 if(iUniqueID != bootSector.UniqueID()) |
|
200 return EFalse; |
|
201 |
|
202 //-- check volume parameters, they must remain the same |
|
203 TFatVolParam volParam; |
|
204 volParam.Populate(bootSector); |
|
205 |
|
206 if(!(volParam == iVolParam)) |
|
207 return EFalse; |
|
208 |
|
209 |
|
210 return ETrue; |
|
211 |
|
212 } |
|
213 //------------------------------------------------------------------------------------------------------------------- |
|
214 |
|
215 /** |
|
216 Helper Method. Check if the parameters of the volume being remounted are the same as current ones. |
|
217 If they are, re-initialises the mount. |
|
218 */ |
|
219 void CFatMountCB::DoReMountL() |
|
220 { |
|
221 |
|
222 if(!CheckVolumeTheSame()) |
|
223 User::Leave(KErrGeneral); |
|
224 |
|
225 //-- get drive capabilities |
|
226 TLocalDriveCapsV2Buf capsBuf; |
|
227 User::LeaveIfError(LocalDrive()->Caps(capsBuf)); |
|
228 |
|
229 //-- the volume is the same as it was on original MountL() |
|
230 //-- we need to re-initialize for the case when the media was removed, FAT or directory structure changed on other device and the media returned back. |
|
231 DoDismount(); |
|
232 |
|
233 SetState(EMounting); |
|
234 |
|
235 InitializeL(capsBuf(), ETrue); //-- forcedly disable FSInfo usage. This will lead to FAT free clusters re-counting. |
|
236 |
|
237 } |
|
238 |
|
239 //------------------------------------------------------------------------------------------------------------------- |
|
240 |
|
241 /** |
|
242 Try remount this Fat volume. Checks if the volume parameters remained the same as on original MountL() call, and |
|
243 if they are, re-initialises the mount. This includes resetting all caches. |
|
244 ! Do not call this method from TFatDriveInterface methods, like citical and non-critical notifiers ! This can lead to the |
|
245 recursive loops and undefined behaviour. |
|
246 |
|
247 @return KErrNone if the remount was OK |
|
248 system-wide error code otherwise |
|
249 */ |
|
250 TInt CFatMountCB::ReMount() |
|
251 { |
|
252 __PRINT2(_L("CFatMountCB::ReMount(), drv:%d, curr state:%d"), DriveNumber(), State()); |
|
253 |
|
254 const TFatMntState currState = State(); |
|
255 |
|
256 //-- analyse the mount state and find out if we can remount at all. |
|
257 switch(currState) |
|
258 { |
|
259 case ENotMounted: |
|
260 __PRINT(_L("CFatMountCB::ReMount() Invalid mount state!")); |
|
261 |
|
262 ASSERT(0); |
|
263 return KErrGeneral; |
|
264 |
|
265 //-- correct state, proceed to remount |
|
266 default: |
|
267 break; |
|
268 } |
|
269 |
|
270 //-- there are 2 options here: |
|
271 //-- 1. normally initialised mount had been forcedly dismounted (it can optionally have objects opened on it) |
|
272 //-- in this case the DoReMountL() will succeed and everything will be fine, the objects will be accessible afterwards |
|
273 //-- 2. the mount hasn't been initialised at all (it does not have for example, FAT table created etc.) |
|
274 //-- in this case we may need to fake the success. This can only happen on forced mount by CFormatCB |
|
275 TInt nRes; |
|
276 TRAP(nRes, DoReMountL()); |
|
277 |
|
278 if(nRes != KErrNone) |
|
279 { |
|
280 //-- note that the mount may be here left in inconsistent state (EMounting) |
|
281 //-- if DoReMountL() fails. This is OK, because we can not make any valid read/write operations in such a state and |
|
282 //-- the drive must be dismounted and mounted again. File Server's TDrive shall do this. |
|
283 __PRINT1(_L("CFatMountCB::ReMount() failed! code:%d"), nRes); |
|
284 |
|
285 //-- If we are in the EInit_Forced state, it means that we are trying to remount the volume that has been formatted. |
|
286 //-- scenario: On formatting, if we can't read a bootsector, new _empty_ object of the CFatMountCB is created and |
|
287 //-- it is used for performing a format. If the format has finished, but RFormat isn't closed yet and we try to access the volume, |
|
288 //-- we will get here, because all members of the constructed mount will be zeroes. |
|
289 if(currState == EInit_Forced) |
|
290 { |
|
291 __PRINT(_L("CFatMountCB::ReMount() simulating normal remount!")); |
|
292 SetState(currState); |
|
293 return KErrNone; |
|
294 } |
|
295 |
|
296 return nRes; |
|
297 } |
|
298 |
|
299 __PRINT1(_L("CFatMountCB::ReMount() Completed drv:%d"), DriveNumber()); |
|
300 SetState(EInit_R); |
|
301 return nRes; |
|
302 } |
|
303 |
|
304 //------------------------------------------------------------------------------------------------------------------- |
|
305 |
|
306 /** |
|
307 Reset the last leaf dir or invalidate leaf dir cache if leaf dir cache is |
|
308 instantiated. |
|
309 */ |
|
310 |
|
311 void CFatMountCB::InvalidateLeafDirCache() |
|
312 { |
|
313 if (iLeafDirCache) |
|
314 { |
|
315 iLeafDirCache->Reset(); |
|
316 } |
|
317 else |
|
318 { |
|
319 User::Free(iLastLeafDir); |
|
320 iLastLeafDir=NULL; |
|
321 } |
|
322 } |
|
323 |
|
324 //------------------------------------------------------------------------------------------------------------------- |
|
325 |
|
326 /** |
|
327 Delete mount's caches |
|
328 Moves CFatMountCB into ENotMounted state immediately. |
|
329 */ |
|
330 void CFatMountCB::DoDismount() |
|
331 { |
|
332 __PRINT1(_L("CFatMountCB::DoDismount() drv:%d"), DriveNumber()); |
|
333 |
|
334 //-- try to flush and destroy FAT cache |
|
335 if (iFatTable) |
|
336 { |
|
337 if(!ConsistentState() || ReadOnly()) |
|
338 {//-- the mount state is inconsistent, so the data can't be flushed. Ignore dirty cache either. |
|
339 iFatTable->Dismount(ETrue); |
|
340 } |
|
341 else |
|
342 {//-- Try to flush the FAT - if this fails there's not much we can do |
|
343 TRAPD(r, iFatTable->FlushL()); |
|
344 iFatTable->Dismount(r != KErrNone); //-- ignore dirty data if we failed to flush the cache |
|
345 } |
|
346 } |
|
347 |
|
348 //-- destroy leafdir name cache, this cache will be re-created while mounting or re-mounting |
|
349 //-- see CFatMountCB::InitializeL() |
|
350 delete iLeafDirCache; |
|
351 iLeafDirCache = NULL; |
|
352 |
|
353 //-- destroy directory cache, this cache will be re-created while mounting or re-mounting |
|
354 //-- see CFatMountCB::InitializeL() |
|
355 delete iRawDisk; |
|
356 iRawDisk = NULL; |
|
357 |
|
358 //-- Set mount state to "Dismounted". Which means that there might be no caches, but the mount is alive, |
|
359 //-- i.e. iFatTable & iRawDisk are valid |
|
360 SetState(EDismounted); |
|
361 } |
|
362 |
|
363 //----------------------------------------------------------------------------------------- |
|
364 |
|
365 /** old implementation */ |
|
366 void CFatMountCB::FinaliseMountL() |
|
367 { |
|
368 FinaliseMountL(RFs::EFinal_RW); |
|
369 } |
|
370 |
|
371 //----------------------------------------------------------------------------------------- |
|
372 /** |
|
373 Dismount the CFatMountCB and the drive. |
|
374 called from TDrive::Dismount(). |
|
375 */ |
|
376 void CFatMountCB::Dismounted() |
|
377 { |
|
378 __PRINT1(_L("CFatMountCB::Dismounted() drv:%d"), DriveNumber()); |
|
379 |
|
380 //-- n.b. it is no safe to do a kind of filnalisatin work here that implies accessing the media. |
|
381 //-- this method may be called after the media change occured from the TDrive::Dismount(). It means |
|
382 //-- that if we try to write some data here, they could be written into a different medium, if it had been |
|
383 //-- physically changed. |
|
384 |
|
385 const TFatMntState prevState = State(); |
|
386 |
|
387 DoDismount(); //-- it will change mount state to EDismounted |
|
388 DismountedLocalDrive(); |
|
389 |
|
390 //-- check if the previous state was EInit_Forced, which means that this method was called |
|
391 //-- on the mount that might not be alive (no valid iFatTable & iRawDisk). |
|
392 //-- This can happen only during format operation on non-mounted previously volume. |
|
393 //-- this EInit_Forced state must be processed separately, see ::Remount() |
|
394 if(prevState == EInit_Forced) |
|
395 SetState(EInit_Forced); |
|
396 |
|
397 } |
|
398 |
|
399 |
|
400 //------------------------------------------------------------------------------------------------------------------- |
|
401 |
|
402 /** |
|
403 Find out if the mount is finalised. |
|
404 @param aFinalised on exit will be ETrue if the maunt is finalised, EFalse otherwise. |
|
405 @return standard error codes. |
|
406 */ |
|
407 TInt CFatMountCB::IsFinalised(TBool& aFinalised) |
|
408 { |
|
409 switch(State()) |
|
410 { |
|
411 case EFinalised: //-- already explicitly finalised |
|
412 aFinalised = ETrue; |
|
413 return KErrNone; |
|
414 |
|
415 case EInit_W: //-- the volume had been written |
|
416 aFinalised = EFalse; |
|
417 return KErrNone; |
|
418 |
|
419 default: //-- it depends on the state |
|
420 break; |
|
421 } |
|
422 |
|
423 //-- find out if the volume is _physically_ finalised. |
|
424 //-- It can be in the state EInit_R, but finalised before mounting |
|
425 if(!VolCleanFlagSupported()) |
|
426 return KErrNotSupported; |
|
427 |
|
428 TInt nRes = KErrNone; |
|
429 TRAP(nRes, aFinalised = VolumeCleanL()); |
|
430 |
|
431 return nRes; |
|
432 } |
|
433 |
|
434 //------------------------------------------------------------------------------------------------------------------- |
|
435 |
|
436 /** |
|
437 @return ETrue if the mount is in consistent state i.e. normally mounted. |
|
438 See TFatMntState enum for more detail. |
|
439 */ |
|
440 TBool CFatMountCB::ConsistentState() const |
|
441 { |
|
442 return (iState==EInit_R) || (iState==EInit_W) || (iState == EFinalised); |
|
443 } |
|
444 |
|
445 //------------------------------------------------------------------------------------------------------------------- |
|
446 |
|
447 /** |
|
448 Open CFatMountCB for write. I.e. perform some actions on the first write attempt. |
|
449 This is a callback from TFatDriveInterface. |
|
450 @return System wide error code. |
|
451 */ |
|
452 TInt CFatMountCB::OpenMountForWrite() |
|
453 { |
|
454 if(State() == EInit_W) |
|
455 return KErrNone; //-- nothing to do, the mount is already opened for write |
|
456 |
|
457 __PRINT1(_L("#- CFatMountCB::OpenMountForWrite() drv:%d\n"),DriveNumber()); |
|
458 |
|
459 ASSERT(State() == EInit_R || State() == EFinalised); |
|
460 |
|
461 //-- Check possible recursion. This method must not be called recursively. SetVolumeCleanL() works through direct disc access and |
|
462 //-- can not call TFatDriveInterface methods that call this method etc. |
|
463 ASSERT(iCBRecFlag == 0); |
|
464 DBG_STATEMENT(iCBRecFlag = 1); //-- set recursion check flag |
|
465 |
|
466 //-- do here some "opening" work, like marking volme as dirty |
|
467 //-- be careful here, as soon as this is a callback from TFatDriveInterface, writing via TFatDriveInterface may cause some unwanted recursion. |
|
468 |
|
469 //-- mark the volume as dirty |
|
470 TInt nRes=KErrNone; |
|
471 TRAP(nRes, SetVolumeCleanL(EFalse)); |
|
472 if(nRes == KErrNone) |
|
473 { |
|
474 SetState(EInit_W); |
|
475 } |
|
476 |
|
477 DBG_STATEMENT(iCBRecFlag = 0); //-- reset recursion check flag |
|
478 |
|
479 return nRes; |
|
480 |
|
481 } |
|
482 |
|
483 //------------------------------------------------------------------------------------------------------------------- |
|
484 |
|
485 /** |
|
486 Unfinalise the mount, reset "VolumeCleanShutDown" flag and change the state if necessarily. |
|
487 */ |
|
488 void CFatMountCB::UnFinaliseMountL() |
|
489 { |
|
490 switch(State()) |
|
491 { |
|
492 case EFinalised: |
|
493 case EInit_R: |
|
494 SetVolumeCleanL(EFalse); //-- the mount, mark volume "dirty" |
|
495 SetState(EInit_R); |
|
496 return; |
|
497 |
|
498 case EInit_W: |
|
499 return; //-- nothing to do |
|
500 |
|
501 default: |
|
502 //-- other mount states are inconsistent; can't perform this operation |
|
503 User::Leave(KErrAbort); |
|
504 break; |
|
505 |
|
506 } |
|
507 |
|
508 } |
|
509 |
|
510 //------------------------------------------------------------------------------------------------------------------- |
|
511 |
|
512 /** |
|
513 Finalise the mount. |
|
514 |
|
515 @param aOperation describes finalisation operation ,see RFs::TFinaliseDrvMode |
|
516 @param aParam1 not used, for future expansion |
|
517 @param aParam2 not used, for future expansion |
|
518 |
|
519 @leave System wide error code. particular cases: |
|
520 KErrArgument invalid arguments |
|
521 KErrInUse if the volume has opened objects (files, directories etc) |
|
522 KErrCorrupt if the volume is corrupt |
|
523 |
|
524 */ |
|
525 void CFatMountCB::FinaliseMountL(TInt aOperation, TAny* /*aParam1*/, TAny* /*aParam2*/) |
|
526 { |
|
527 __PRINT2(_L("#- CFatMountCB::FinaliseMountL() op:%d, drv:%d"), aOperation, DriveNumber()); |
|
528 |
|
529 switch(aOperation) |
|
530 { |
|
531 case RFs::EFinal_RW: |
|
532 case RFs::EFinal_RO: |
|
533 break; |
|
534 |
|
535 case RFs::EForceUnfinalise: |
|
536 UnFinaliseMountL(); |
|
537 return; |
|
538 |
|
539 default: |
|
540 __PRINT1(_L("#- CFatMountCB::FinaliseMountL() unexpected operation!:%d"), aOperation); |
|
541 ASSERT(0); |
|
542 User::Leave(KErrArgument); |
|
543 return; |
|
544 } |
|
545 |
|
546 //-- mount finalisation work |
|
547 |
|
548 ASSERT(aOperation == RFs::EFinal_RW || aOperation == RFs::EFinal_RO); |
|
549 |
|
550 if(State() == EFinalised) |
|
551 {//-- the mount is already finalised. All we can do is to set it to RO mode |
|
552 if(ReadOnly() && aOperation == RFs::EFinal_RW) |
|
553 { |
|
554 User::Leave(KErrAccessDenied); //-- can't override RO flag |
|
555 } |
|
556 |
|
557 (void)LocalDrive()->Finalise(ETrue); |
|
558 |
|
559 if(aOperation == RFs::EFinal_RO) |
|
560 { |
|
561 SetReadOnly(ETrue); |
|
562 return; |
|
563 } |
|
564 |
|
565 return; |
|
566 } |
|
567 |
|
568 if(LockStatus() != 0) |
|
569 {//-- can't finalise the volume if it has opened objects and not in the consistent state. |
|
570 //-- Theoretically, we can finalise the mount if we have files opened only for read, but at present, |
|
571 //-- it's impossible to detect such situation. |
|
572 User::Leave(KErrInUse); |
|
573 } |
|
574 |
|
575 if(State() != EInit_R && State() != EInit_W) |
|
576 {//-- can't finalise the mount because it can be in an inconsistent state; e.g. corrupt. |
|
577 __PRINT1(_L("#- CFatMountCB::FinaliseMountL() Invalid mount State: %d"),State()); |
|
578 User::Leave(KErrCorrupt); |
|
579 } |
|
580 |
|
581 //-- flush FAT cache |
|
582 FAT().FlushL(); |
|
583 |
|
584 //-- for FAT32 we may need to update data in FSInfo sectors |
|
585 if(Is32BitFat()) |
|
586 { |
|
587 if(FAT().ConsistentState()) |
|
588 {//-- FAT table state is consistent and the number of free clusters is known. |
|
589 //-- Do it disregarding the mount state, it may help in the situation when 2 copies of the FSInfo are different for some reason. |
|
590 DoUpdateFSInfoSectorsL(EFalse); |
|
591 } |
|
592 else |
|
593 {//-- FAT table state is inconsistent, the most probable case here: background scan for free clusters is still working. |
|
594 //-- in this case we can't put corect values into the FSInfo. |
|
595 if(State() == EInit_W) |
|
596 {//-- bad situation: free clusters may be being counted and someone has already written something on the volume at the same time. |
|
597 //-- we do not know the exact number of free clustes and can't wait until scan finishes. Invalidate FSInfo. |
|
598 __PRINT(_L("#- CFatMountCB::FinaliseMountL() invalidating FSInfo")); |
|
599 DoUpdateFSInfoSectorsL(ETrue); |
|
600 } |
|
601 else |
|
602 {//-- no changes on the volume, just do not update FSInfo |
|
603 __PRINT(_L("#- CFatMountCB::FinaliseMountL() FAT state inconsistent; FSInfo isn't updated")); |
|
604 } |
|
605 |
|
606 }//if(FAT().ConsistentState()) |
|
607 |
|
608 }//if(Is32BitFat()) |
|
609 |
|
610 |
|
611 |
|
612 //-- mark the volume as clean |
|
613 SetVolumeCleanL(ETrue); |
|
614 |
|
615 //-- finally, put the volume into RO mode if required |
|
616 if(aOperation == RFs::EFinal_RO) |
|
617 SetReadOnly(ETrue); |
|
618 |
|
619 SetState(EFinalised); |
|
620 } |
|
621 |
|
622 |
|
623 //------------------------------------------------------------------------------------------------------------------- |
|
624 |
|
625 /** |
|
626 @return ETrue if "VolumeClean" flag is supported i.e. this is not FAT12 |
|
627 */ |
|
628 TBool CFatMountCB::VolCleanFlagSupported() const |
|
629 { |
|
630 const TFatType fatType=FatType(); |
|
631 |
|
632 ASSERT(fatType == EFat12 || fatType == EFat16 || fatType == EFat32); |
|
633 return (fatType != EFat12); |
|
634 } |
|
635 |
|
636 //----------------------------------------------------------------------------------------- |
|
637 |
|
638 |
|
639 /** |
|
640 Obtain the volume information. |
|
641 All information except iSize and iFree has been added by TDrive::Volume(). |
|
642 |
|
643 @param aVolume on return will contain iSize & iFree fields filled with actual data. |
|
644 */ |
|
645 void CFatMountCB::VolumeL(TVolumeInfo& aVolume) const |
|
646 { |
|
647 |
|
648 //-- if true, this operation will be synchronous, i.e the client will be suspended until FAT32 scanning thread finishes, if running. |
|
649 //-- the information if this operation is synchronous or not can be passed by client in TVolumeInfo::iFileCacheFlags field. |
|
650 //-- if the client sets aVolume.iVolSizeAsync flag there, RFs::Volume() will be asynchronous, i.e the _current_ number of free clusters |
|
651 //-- will be returned. |
|
652 const TBool bSyncOp = !aVolume.iVolSizeAsync; |
|
653 aVolume.iVolSizeAsync = EFalse; //-- reset this flag in order it not to be reused on the client side |
|
654 |
|
655 __PRINT2(_L("CFatMountCB::VolumeL() drv:%d, synch:%d"), DriveNumber(), bSyncOp); |
|
656 const TDriveInfo& drvInfo=aVolume.iDrive; |
|
657 |
|
658 #if defined(__EPOC32__) |
|
659 // if RAM drive, cap size according to HAL. |
|
660 if (drvInfo.iType==EMediaRam) |
|
661 { |
|
662 TLocalDriveCapsV2Buf caps; |
|
663 LocalDrive()->Caps(caps); |
|
664 |
|
665 const TInt max_drive_size=TInt(caps().iEraseBlockSize); |
|
666 const TInt cur_drive_size=I64INT(caps().iSize); |
|
667 |
|
668 aVolume.iSize=max_drive_size; |
|
669 aVolume.iFree=max_drive_size-cur_drive_size; |
|
670 |
|
671 aVolume.iSize=aVolume.iFree+iSize; |
|
672 |
|
673 TInt maxSize; |
|
674 if (HAL::Get(HAL::EMaxRAMDriveSize, maxSize) == KErrNone) |
|
675 { |
|
676 // iSize will never grow beyond maxRam because of a check in medint. |
|
677 // d <= f; (s{f} + f) - m <= f; s{f} <= m |
|
678 __ASSERT_DEBUG(iSize <= maxSize, Fault(EFatRAMDriveSizeInvalid)); |
|
679 if (aVolume.iSize > maxSize) |
|
680 { |
|
681 TInt64 d = aVolume.iSize - maxSize; |
|
682 __ASSERT_DEBUG(d <= aVolume.iFree, Fault(EFatRAMDriveFreeInvalid)); |
|
683 aVolume.iSize -= d; |
|
684 aVolume.iFree -= d; |
|
685 } |
|
686 } |
|
687 |
|
688 aVolume.iSize-=ClusterBasePosition(); // Allow for bytes used by FAT etc |
|
689 aVolume.iSize=(aVolume.iSize>>ClusterSizeLog2())<<ClusterSizeLog2(); //-- round down to cluster size |
|
690 |
|
691 return; |
|
692 }//if (drvInfo.iType==EMediaRam) |
|
693 |
|
694 #endif |
|
695 |
|
696 |
|
697 const TUint32 freeClusters = FAT().NumberOfFreeClusters(bSyncOp); |
|
698 |
|
699 __PRINT1(_L("CFatMountCB::VolumeL() free clusters:%d"), freeClusters); |
|
700 |
|
701 aVolume.iFree = (TInt64)freeClusters << ClusterSizeLog2(); |
|
702 |
|
703 if (drvInfo.iType==EMediaRam) |
|
704 aVolume.iSize=aVolume.iFree+iSize; |
|
705 |
|
706 aVolume.iSize-=ClusterBasePosition(); // Allow for bytes used by FAT etc |
|
707 aVolume.iSize=(aVolume.iSize >> ClusterSizeLog2()) << ClusterSizeLog2(); //-- round down to cluster size |
|
708 |
|
709 } |
|
710 |
|
711 |
|
712 //----------------------------------------------------------------------------------------- |
|
713 |
|
714 // |
|
715 // Set the volume label (write aVolume label into BPB & Volume Label File) |
|
716 // aName string may be zero length but is assumed to contain no illegal characters or NULLs. |
|
717 // |
|
718 void CFatMountCB::SetVolumeL(TDes& aName) |
|
719 { |
|
720 |
|
721 __PRINT(_L("CFatMountCB::SetVolumeL")); |
|
722 |
|
723 CheckStateConsistentL(); |
|
724 CheckWritableL(); |
|
725 |
|
726 __ASSERT_ALWAYS(aName.Length()<=KVolumeLabelSize,User::Leave(KErrBadName)); |
|
727 |
|
728 TBuf8<KVolumeLabelSize> buf8(KVolumeLabelSize); |
|
729 buf8.Zero(); |
|
730 LocaleUtils::ConvertFromUnicodeL(buf8, aName, TFatUtilityFunctions::EOverflowActionLeave); |
|
731 aName.Zero(); |
|
732 LocaleUtils::ConvertToUnicodeL(aName, buf8); // adjust aName (which may contain more underscores after this line than before) |
|
733 |
|
734 const TInt lengthOfBuf8=buf8.Length(); |
|
735 // Pad to end with spaces if not empty. |
|
736 if (lengthOfBuf8>0 && lengthOfBuf8<KVolumeLabelSize) |
|
737 { |
|
738 buf8.SetLength(KVolumeLabelSize); |
|
739 Mem::Fill(&buf8[lengthOfBuf8],KVolumeLabelSize-lengthOfBuf8,' '); |
|
740 } |
|
741 |
|
742 // Write a volume label file |
|
743 WriteVolumeLabelFileL( buf8 ); |
|
744 |
|
745 // Write the boot sector volume label |
|
746 // Always pad to full length with spaces |
|
747 if (lengthOfBuf8==0) |
|
748 { |
|
749 buf8.Fill(' ',KVolumeLabelSize); |
|
750 } |
|
751 |
|
752 WriteVolumeLabelL(buf8); |
|
753 } |
|
754 |
|
755 //----------------------------------------------------------------------------------------- |
|
756 |
|
757 /** |
|
758 Make a directory. |
|
759 @param aName full path to the directory to create. Name validity is checked by file server. |
|
760 all trailing dots from the name will be removed |
|
761 */ |
|
762 void CFatMountCB::MkDirL(const TDesC& aName) |
|
763 { |
|
764 __PRINT2(_L("CFatMountCB::MkDirL, drv:%d, %S"), DriveNumber(), &aName); |
|
765 |
|
766 CheckStateConsistentL(); |
|
767 CheckWritableL(); |
|
768 |
|
769 TPtrC dirName = RemoveTrailingDots(aName); //-- remove trailing dots from the name |
|
770 |
|
771 TInt namePos=dirName.LocateReverse(KPathDelimiter)+1; // There is always a path delimiter |
|
772 TPtrC name=dirName.Mid(namePos); |
|
773 TLeafDirData leafDir; |
|
774 const TEntryPos dirPos(FindLeafDirL(dirName.Left(namePos), leafDir),0); |
|
775 TEntryPos dumPos=dirPos; |
|
776 TFatDirEntry dumEntry; |
|
777 |
|
778 TBool isOriginalNameLegal = IsLegalDosName(name,EFalse,EFalse,EFalse,EFalse,ETrue); |
|
779 iFileCreationHelper.InitialiseL(name); |
|
780 TFileName fileName; |
|
781 TEntryPos startPos; |
|
782 TFatDirEntry startEntry; |
|
783 |
|
784 TRAPD(ret,DoFindL(name,KEntryAttMaskSupported, |
|
785 startPos,startEntry,dumPos,dumEntry, |
|
786 fileName,KErrNotFound, |
|
787 &iFileCreationHelper, |
|
788 leafDir)); |
|
789 |
|
790 if (ret!=KErrNotFound && ret!=KErrNone) |
|
791 User::Leave(ret); |
|
792 if (ret!=KErrNotFound) |
|
793 { |
|
794 if (dumEntry.Attributes()&KEntryAttDir) |
|
795 User::Leave(KErrAlreadyExists); |
|
796 else |
|
797 User::Leave(KErrAccessDenied); |
|
798 } |
|
799 TShortName shortName; |
|
800 |
|
801 if (iFileCreationHelper.GetValidatedShortName(shortName) == KErrNotFound) |
|
802 { |
|
803 GenerateShortNameL(dirPos.iCluster,name,shortName,ETrue); |
|
804 } |
|
805 |
|
806 TInt numEntries=1; |
|
807 if (isOriginalNameLegal==EFalse) |
|
808 numEntries=NumberOfVFatEntries(name.Length()); |
|
809 dumPos=dirPos; |
|
810 |
|
811 if (iFileCreationHelper.IsNewEntryPosFound()) |
|
812 { |
|
813 dumPos = iFileCreationHelper.EntryAddingPos(); |
|
814 } |
|
815 |
|
816 AddDirEntryL(dumPos,numEntries); // Directory entry in leaf directory |
|
817 TInt startCluster; |
|
818 FOREVER |
|
819 { |
|
820 //-- FAT().FreeClusterHint() will give us a hint of the last free cluster |
|
821 startCluster=FAT().AllocateSingleClusterL(dumPos.iCluster ? dumPos.iCluster : FAT().FreeClusterHint()); |
|
822 |
|
823 FAT().FlushL(); |
|
824 TRAPD(r, InitializeFirstDirClusterL(startCluster,dirPos.iCluster)); |
|
825 if(r == KErrNone) |
|
826 break; |
|
827 if(r != KErrCorrupt) |
|
828 User::Leave(r); |
|
829 FAT().MarkAsBadClusterL(startCluster); |
|
830 } |
|
831 TFatDirEntry fatDirEntry; |
|
832 fatDirEntry.SetName(shortName); |
|
833 fatDirEntry.SetAttributes(KEntryAttDir); |
|
834 TTime now; |
|
835 now.UniversalTime(); |
|
836 fatDirEntry.SetTime(now, TimeOffset()); |
|
837 fatDirEntry.SetCreateTime(now, TimeOffset()); |
|
838 fatDirEntry.SetStartCluster(startCluster); |
|
839 fatDirEntry.SetSize(0); |
|
840 if (isOriginalNameLegal) |
|
841 WriteDirEntryL(dumPos,fatDirEntry); |
|
842 else |
|
843 WriteDirEntryL(dumPos,fatDirEntry,name); |
|
844 |
|
845 iFileCreationHelper.Close(); |
|
846 } |
|
847 |
|
848 //----------------------------------------------------------------------------------------- |
|
849 |
|
850 /** |
|
851 Setup 1st cluster of the new directory |
|
852 |
|
853 @param aStartCluster this entry start cluster number |
|
854 @param aParentCluster parent entry start cluster number |
|
855 */ |
|
856 void CFatMountCB::InitializeFirstDirClusterL(TInt aStartCluster,TInt aParentCluster) |
|
857 { |
|
858 const TUint32 KClusterSz= 1<<ClusterSizeLog2(); |
|
859 const TUint32 KMaxBufSz = KClusterSz; //-- max. nuffer size is a cluster |
|
860 const TUint32 KMinBufSz = 1<<SectorSizeLog2(); //-- min. buffer size is 1 sector (for OOM case) |
|
861 |
|
862 //-- allocate a buffer for directory file 1st cluster initialisation |
|
863 RBuf8 buf; |
|
864 CleanupClosePushL(buf); |
|
865 |
|
866 if(buf.CreateMax(KMaxBufSz) != KErrNone) |
|
867 buf.CreateMaxL(KMinBufSz); //-- OOM, try to create smaller buffer |
|
868 |
|
869 buf.FillZ(); |
|
870 |
|
871 //-- copy "." directory entry to the buffer |
|
872 |
|
873 //-- "." directory entry |
|
874 TFatDirEntry entry; |
|
875 TTime now; |
|
876 now.UniversalTime(); |
|
877 entry.SetTime(now, TimeOffset() ); |
|
878 entry.SetAttributes(KEntryAttDir); |
|
879 entry.SetCurrentDirectory(); |
|
880 entry.SetStartCluster(aStartCluster); |
|
881 Mem::Copy(&buf[0],&entry,KSizeOfFatDirEntry); |
|
882 |
|
883 //-- append ".." directory entry |
|
884 entry.SetParentDirectory(); |
|
885 entry.SetStartCluster(aParentCluster==RootIndicator() ? 0 : aParentCluster); |
|
886 Mem::Copy(&buf[0]+KSizeOfFatDirEntry,&entry,KSizeOfFatDirEntry); |
|
887 |
|
888 TEntryPos entryPos(aStartCluster,0); |
|
889 |
|
890 //-- write buffer to the beginning of the directory file. |
|
891 DirWriteL(entryPos, buf); //-- use special interface to access FAT directory file |
|
892 |
|
893 //-- fill in the rest of the cluster if we used a small buffer |
|
894 if((TUint32)buf.Size() < KClusterSz) //-- use special interface to access FAT directory file |
|
895 { |
|
896 buf.FillZ(); |
|
897 const TInt restCnt = SectorsPerCluster() - 1; |
|
898 ASSERT(restCnt >=1); |
|
899 |
|
900 for(TInt i=0; i<restCnt; ++i) |
|
901 { |
|
902 entryPos.iPos += KMinBufSz; |
|
903 DirWriteL(entryPos, buf); //-- use directory cache when dealing with directories |
|
904 } |
|
905 |
|
906 } |
|
907 |
|
908 CleanupStack::PopAndDestroy(&buf); |
|
909 |
|
910 } |
|
911 |
|
912 //----------------------------------------------------------------------------------------- |
|
913 |
|
914 /** |
|
915 Remove a directory. |
|
916 @param aName directory name |
|
917 all trailing dots from the name will be removed |
|
918 */ |
|
919 void CFatMountCB::RmDirL(const TDesC& aName) |
|
920 { |
|
921 __PRINT2(_L("CFatMountCB::RmDirL, drv:%d, %S"), DriveNumber(), &aName); |
|
922 |
|
923 CheckStateConsistentL(); |
|
924 CheckWritableL(); |
|
925 |
|
926 TPtrC dirName = RemoveTrailingDots(aName); //-- remove trailing dots from the name |
|
927 |
|
928 TFatDirEntry dirEntry; |
|
929 TEntryPos dirEntryPos(RootIndicator(),0); // Already checked entry is a directory |
|
930 FindEntryStartL(dirName,KEntryAttMatchMask|KEntryAttMatchExclusive,dirEntry,dirEntryPos); |
|
931 TEntryPos dosEntryPos=dirEntryPos; |
|
932 TFatDirEntry dosEntry=dirEntry; |
|
933 MoveToDosEntryL(dosEntryPos,dosEntry); |
|
934 if (!IsDirectoryEmptyL(StartCluster(dosEntry))) |
|
935 User::Leave(KErrInUse); |
|
936 // Remove the directory from cache before erasing |
|
937 if(iLeafDirCache && iLeafDirCache->CacheCount() > 0) |
|
938 { |
|
939 iLeafDirCache->RemoveDirL(StartCluster(dosEntry)); |
|
940 } |
|
941 |
|
942 EraseDirEntryL(dirEntryPos,dirEntry); |
|
943 FAT().FreeClusterListL(StartCluster(dosEntry)); |
|
944 FAT().FlushL(); |
|
945 } |
|
946 |
|
947 //----------------------------------------------------------------------------------------- |
|
948 |
|
949 /** |
|
950 Delete a file |
|
951 @param aName file name |
|
952 all trailing dots from the name will be removed |
|
953 */ |
|
954 void CFatMountCB::DeleteL(const TDesC& aName) |
|
955 { |
|
956 __PRINT2(_L("CFatMountCB::DeleteL, drv:%d, %S"), DriveNumber(), &aName); |
|
957 |
|
958 CheckStateConsistentL(); |
|
959 CheckWritableL(); |
|
960 |
|
961 TPtrC fullName = RemoveTrailingDots(aName); //-- remove trailing dots from the name |
|
962 |
|
963 TFatDirEntry firstEntry; |
|
964 TEntryPos firstEntryPos(RootIndicator(),0); |
|
965 FindEntryStartL(fullName,KEntryAttMaskSupported,firstEntry,firstEntryPos); |
|
966 TEntryPos dosEntryPos=firstEntryPos; |
|
967 TFatDirEntry dosEntry=firstEntry; |
|
968 MoveToDosEntryL(dosEntryPos,dosEntry); |
|
969 if ((dosEntry.Attributes()&KEntryAttReadOnly) || (dosEntry.Attributes()&KEntryAttDir)) |
|
970 User::Leave(KErrAccessDenied); |
|
971 // Can not delete a file if it is clamped |
|
972 CMountCB* basePtr=(CMountCB*)this; |
|
973 TInt startCluster=StartCluster(dosEntry); |
|
974 if(basePtr->IsFileClamped(MAKE_TINT64(0,startCluster)) > 0) |
|
975 User::Leave(KErrInUse); |
|
976 EraseDirEntryL(firstEntryPos,firstEntry); |
|
977 FAT().FreeClusterListL(StartCluster(dosEntry)); |
|
978 FAT().FlushL(); |
|
979 } |
|
980 |
|
981 //----------------------------------------------------------------------------------------- |
|
982 |
|
983 /** |
|
984 |
|
985 Rename or replace a directory entry. |
|
986 Assumes all files are closed and replace is only passed files. |
|
987 Assumes rename target does not exist or is the source file. |
|
988 |
|
989 --------------- operating mode -------------------------------------------- |
|
990 |
|
991 * rename mode |
|
992 |
|
993 aOldName exists | aNewName exists | result |
|
994 N N leave KErrNotFound |
|
995 N Y leave KErrNotFound |
|
996 Y N rename aOldName -> aNewName |
|
997 Y Y leave KErrAlreadyExists if(aOldName!=aNewName); otherwise do nothing |
|
998 |
|
999 * replace mode |
|
1000 |
|
1001 N N leave KErrNotFound |
|
1002 N Y leave KErrNotFound |
|
1003 Y N rename aOldName -> aNewName |
|
1004 Y Y contents and all file attributes of the "aNewName" are replaced with aOldName's. "aOldName" entries are deleted then. |
|
1005 |
|
1006 |
|
1007 @param aOldName entry name to be renamed or replaced |
|
1008 @param aNewName a new entry name |
|
1009 @param aMode specifies renaming / replacing |
|
1010 @param aNewDosEntryPos on exit contains new entry Pos. |
|
1011 */ |
|
1012 void CFatMountCB::DoRenameOrReplaceL(const TDesC& aOldName, const TDesC& aNewName, TRenMode aMode, TEntryPos& aNewName_DosEntryPos) |
|
1013 { |
|
1014 __PRINT3(_L("CFatMountCB::DoRenameOrReplaceL() mode:%d old:%S, new:%S"), aMode, &aOldName, &aNewName); |
|
1015 |
|
1016 const TBool namesAreIdentical = FileNamesIdentical(aOldName, aNewName); //-- this is case-insensitive. |
|
1017 const TBool renameMode = (aMode == EModeRename); |
|
1018 const TBool replaceMode = !renameMode; |
|
1019 TInt nRes; |
|
1020 |
|
1021 if(namesAreIdentical && replaceMode) |
|
1022 return; //-- nothing to do, replacing file with itself |
|
1023 |
|
1024 //--------------------------------------------------------------------------------------------------------------------------- |
|
1025 //-- 1. find the entries of 'aOldName' file. It must always succeed, because FileServer firstly tries to locate 'aOldName' |
|
1026 |
|
1027 TFatDirEntry oldName_FirstEntry; //-- first entry of the "aOldName" entryset |
|
1028 TEntryPos oldName_FirstEntryPos(RootIndicator(), 0); //-- dir. pos of the start "aOldName" VFAT entry set |
|
1029 |
|
1030 FindEntryStartL(aOldName, KEntryAttMaskSupported, oldName_FirstEntry, oldName_FirstEntryPos); |
|
1031 |
|
1032 TFatDirEntry oldName_DosEntry = oldName_FirstEntry; //-- "aOldName" entry set DOS entry |
|
1033 TEntryPos oldName_DosEntryPos = oldName_FirstEntryPos;//-- dir. pos of the "aOldName" DOS entry |
|
1034 |
|
1035 MoveToDosEntryL(oldName_DosEntryPos, oldName_DosEntry); |
|
1036 |
|
1037 const TBool bOldNameIsVFAT = !(oldName_DosEntryPos == oldName_FirstEntryPos); //-- ETrue if "aOldName" is VFAT name, i.e. consists of mode than 1 entry |
|
1038 |
|
1039 //-- check if the file "aOldName" is clamped. In this case it can't be replaced. |
|
1040 if(replaceMode && (IsFileClamped(StartCluster(oldName_DosEntry)) > 0)) |
|
1041 User::Leave(KErrInUse); |
|
1042 |
|
1043 //--------------------------------------------------------------------------------------------------------------------------- |
|
1044 //-- 2. find the entry of 'aNewName' file. Further behavior depends on rename/replace mode and if this file exists or not |
|
1045 |
|
1046 //-- extract new file name from the full path |
|
1047 TPtrC ptrNewName; |
|
1048 TPtrC ptrNewNameParentDir; |
|
1049 const TInt delimPos = aNewName.LocateReverse(KPathDelimiter); |
|
1050 ptrNewName.Set(aNewName.Mid(delimPos+1)); |
|
1051 ptrNewNameParentDir.Set(aNewName.Left(delimPos+1)); |
|
1052 |
|
1053 //-- find the parent directory of the "aNewName" and create iterator for it |
|
1054 TLeafDirData leafDir; |
|
1055 const TEntryPos aNewName_ParentDirPos = TEntryPos(FindLeafDirL(ptrNewNameParentDir, leafDir), 0); //-- 'aNewName' parent directory iterator |
|
1056 aNewName_DosEntryPos = aNewName_ParentDirPos; |
|
1057 |
|
1058 TEntryPos newName_VFatEntryPos; //-- dir. pos of the start "aNewName" VFAT entry set |
|
1059 TFatDirEntry newName_DosEntry; |
|
1060 |
|
1061 TFileName fileName; |
|
1062 iFileCreationHelper.InitialiseL(ptrNewName); |
|
1063 TFatDirEntry startEntry; |
|
1064 |
|
1065 TRAP(nRes, DoFindL(ptrNewName, KEntryAttMaskSupported, |
|
1066 newName_VFatEntryPos, startEntry, aNewName_DosEntryPos, newName_DosEntry, |
|
1067 fileName, KErrNotFound, |
|
1068 &iFileCreationHelper, |
|
1069 leafDir)); |
|
1070 |
|
1071 if (nRes!=KErrNone && nRes!=KErrNotFound) |
|
1072 User::Leave(nRes); |
|
1073 |
|
1074 const TBool newFileExists = (nRes == KErrNone); //-- ETrue if 'aNewName' file exists. |
|
1075 const TBool bNewNameIsVFAT = !IsLegalDosName(ptrNewName, EFalse, EFalse, EFalse, EFalse, ETrue); |
|
1076 |
|
1077 if(renameMode && newFileExists) |
|
1078 { |
|
1079 if(!namesAreIdentical) |
|
1080 { |
|
1081 if ((newName_DosEntry.Attributes()&KEntryAttDir) != (oldName_DosEntry.Attributes()&KEntryAttDir)) |
|
1082 { |
|
1083 User::Leave(KErrAccessDenied); //-- leave with KErrAccessDenied if it is trying to rename a file |
|
1084 // to a dir or vice versa. |
|
1085 } |
|
1086 User::Leave(KErrAlreadyExists); //-- can't rename file if the file with 'aNewName' already exists |
|
1087 } |
|
1088 else |
|
1089 { |
|
1090 if(!bNewNameIsVFAT && !bOldNameIsVFAT) |
|
1091 return; //-- renaming DOS name to itself |
|
1092 } |
|
1093 //-- allow renaming entry to itself. "namesAreIdentical" is case-insensitive. use case: "FILE" -> "File" |
|
1094 } |
|
1095 |
|
1096 //--------------------------------------------------------------------------------------------------------------------------- |
|
1097 |
|
1098 if(replaceMode && newFileExists) |
|
1099 { |
|
1100 //--------------------------------------------------------------------------------------------------------------------------- |
|
1101 //-- replace contents of the 'aNewName' with 'aOldName' and remove 'aOldName' entries. |
|
1102 |
|
1103 //-- check if we are still trying to replace the file with itself, probably using short name alias |
|
1104 if(aNewName_DosEntryPos == oldName_DosEntryPos) |
|
1105 return; //-- nothing to do, it's the same file |
|
1106 |
|
1107 const TInt oldNameStartCluster = StartCluster(oldName_DosEntry); |
|
1108 const TInt newNameStartCluster = StartCluster(newName_DosEntry); //-- store starting cluster of the chain to be unlinked |
|
1109 |
|
1110 newName_DosEntry.SetStartCluster(oldNameStartCluster); |
|
1111 newName_DosEntry.SetSize(oldName_DosEntry.Size()); |
|
1112 newName_DosEntry.SetTime(oldName_DosEntry.Time(TTimeIntervalSeconds(0)), TTimeIntervalSeconds(0)); |
|
1113 newName_DosEntry.SetAttributes(oldName_DosEntry.Attributes()); |
|
1114 |
|
1115 if(IsRuggedFSys()) |
|
1116 { |
|
1117 //-- Note 1. |
|
1118 //-- set a special Id in reserved section for old and new entries. |
|
1119 //-- if write fails before the old entry gets erased, we will have 2 entries pointing to the same clusterchain. |
|
1120 //-- ScanDrive is responsible for fixing this situation by erasing entry with ID KReservedIdOldEntry. |
|
1121 //-- note that SetRuggedFatEntryId() uses "LastAccessTime" DOS FAT entry field to store the ID. |
|
1122 //-- in normal situation this field isn't used, though Windows checkdisk can chack its validiy. |
|
1123 //-- KReservedIdNewEntry == 0x0000 that corresponds to year 1980. |
|
1124 |
|
1125 newName_DosEntry.SetRuggedFatEntryId(KReservedIdNewEntry); |
|
1126 oldName_DosEntry.SetRuggedFatEntryId(KReservedIdOldEntry); |
|
1127 WriteDirEntryL(oldName_DosEntryPos, oldName_DosEntry); |
|
1128 } |
|
1129 |
|
1130 //-- write 'aNewName' DOS dir. entry data back |
|
1131 WriteDirEntryL(aNewName_DosEntryPos, newName_DosEntry); |
|
1132 |
|
1133 //-- erase "oldName" entryset. |
|
1134 EraseDirEntryL(oldName_FirstEntryPos, oldName_FirstEntry); |
|
1135 |
|
1136 //-- free 'aNewName' cluster list |
|
1137 FAT().FreeClusterListL(newNameStartCluster); |
|
1138 |
|
1139 if(IsRuggedFSys()) |
|
1140 FAT().FlushL(); |
|
1141 |
|
1142 } |
|
1143 else //if(replaceMode && newFileExists) |
|
1144 { |
|
1145 //--------------------------------------------------------------------------------------------------------------------------- |
|
1146 //-- Renaming 'aOldName' to 'aNewName': add 'aNewName' entry set and remove 'aOldName' entryset |
|
1147 |
|
1148 TFatDirEntry newDosEntry = oldName_DosEntry; |
|
1149 //-- generate short name for the 'aNewName' entryset and make new DOS entry |
|
1150 if(bNewNameIsVFAT) |
|
1151 {//-- need to generate a short name for VFAT entryset DOS entry |
|
1152 TShortName shortName; |
|
1153 |
|
1154 if (iFileCreationHelper.GetValidatedShortName(shortName) == KErrNotFound) |
|
1155 { |
|
1156 GenerateShortNameL(aNewName_DosEntryPos.Cluster(), ptrNewName, shortName, ETrue); |
|
1157 } |
|
1158 |
|
1159 newDosEntry.SetName(shortName); |
|
1160 } |
|
1161 else |
|
1162 {//-- just use 'aNewName' as DOS name. |
|
1163 TBuf8<KFatDirNameSize+1> tmp; //-- the name may be "XXXXXXXX.YYY" |
|
1164 tmp.Copy(ptrNewName); |
|
1165 newDosEntry.SetName(DosNameToStdFormat(tmp)); |
|
1166 } |
|
1167 |
|
1168 if(IsRuggedFSys()) |
|
1169 {//-- the the note(1) above |
|
1170 newDosEntry.SetRuggedFatEntryId(KReservedIdNewEntry); |
|
1171 oldName_DosEntry.SetRuggedFatEntryId(KReservedIdOldEntry); |
|
1172 WriteDirEntryL(oldName_DosEntryPos, oldName_DosEntry); |
|
1173 } |
|
1174 |
|
1175 //-- add new entryset to the directory |
|
1176 aNewName_DosEntryPos.iPos = 0; |
|
1177 aNewName_DosEntryPos.iCluster = aNewName_ParentDirPos.Cluster(); |
|
1178 |
|
1179 if (iFileCreationHelper.IsNewEntryPosFound()) |
|
1180 { |
|
1181 aNewName_DosEntryPos = iFileCreationHelper.EntryAddingPos(); |
|
1182 } |
|
1183 |
|
1184 if(bNewNameIsVFAT) |
|
1185 { |
|
1186 const TInt numEntries = NumberOfVFatEntries(ptrNewName.Length()); |
|
1187 AddDirEntryL(aNewName_DosEntryPos, numEntries); |
|
1188 WriteDirEntryL(aNewName_DosEntryPos, newDosEntry, ptrNewName); |
|
1189 } |
|
1190 else |
|
1191 {//-- new name is one DOS entry only |
|
1192 AddDirEntryL(aNewName_DosEntryPos, 1); |
|
1193 WriteDirEntryL(aNewName_DosEntryPos, newDosEntry); |
|
1194 } |
|
1195 |
|
1196 //-- erase old entryset. |
|
1197 EraseDirEntryL(oldName_FirstEntryPos, oldName_FirstEntry); |
|
1198 |
|
1199 //-- if we have renamed (moved) a directory, need to update its pointer to parent directory ('..' entry) |
|
1200 if((newDosEntry.Attributes() & KEntryAttDir)) |
|
1201 { |
|
1202 TEntryPos parentPtrEntPos(StartCluster(newDosEntry), 1*KSizeOfFatDirEntry); |
|
1203 |
|
1204 TFatDirEntry chFatEnt; |
|
1205 ReadDirEntryL(parentPtrEntPos, chFatEnt); |
|
1206 |
|
1207 const TUint parentDirStartCluster_Old = StartCluster(chFatEnt); |
|
1208 TUint parentDirStartCluster_New = aNewName_ParentDirPos.Cluster(); |
|
1209 |
|
1210 if(parentDirStartCluster_New == RootClusterNum() && parentDirStartCluster_New != 0) |
|
1211 {//-- we are in the root directory. for some reason, '..' entries of the directories in the root dir. |
|
1212 //-- must have starting cluster 0 |
|
1213 parentDirStartCluster_New = 0; |
|
1214 } |
|
1215 |
|
1216 if(parentDirStartCluster_Old != parentDirStartCluster_New) |
|
1217 { |
|
1218 chFatEnt.SetStartCluster(parentDirStartCluster_New); |
|
1219 WriteDirEntryL(parentPtrEntPos, chFatEnt); |
|
1220 } |
|
1221 // Invalidate leaf dir cache as it is hard to track the dir structure changes now |
|
1222 if (iLeafDirCache) |
|
1223 { |
|
1224 iLeafDirCache->Reset(); |
|
1225 } |
|
1226 } |
|
1227 }//else if(replaceMode && newFileExists) |
|
1228 |
|
1229 iFileCreationHelper.Close(); |
|
1230 } |
|
1231 |
|
1232 //----------------------------------------------------------------------------------------- |
|
1233 |
|
1234 /** |
|
1235 Rename 'aOldName' file/directory to 'aNewName' |
|
1236 all trailing dots from the names will be removed |
|
1237 |
|
1238 @param aOldName existing object name |
|
1239 @param aNewName new object name |
|
1240 */ |
|
1241 void CFatMountCB::RenameL(const TDesC& aOldName, const TDesC& aNewName) |
|
1242 { |
|
1243 __PRINT3(_L("CFatMountCB::RenameL, drv:%d, %S %S"), DriveNumber(), &aOldName, &aNewName); |
|
1244 |
|
1245 CheckStateConsistentL(); |
|
1246 CheckWritableL(); |
|
1247 |
|
1248 TEntryPos newEntryPos; |
|
1249 DoRenameOrReplaceL(RemoveTrailingDots(aOldName), RemoveTrailingDots(aNewName) ,EModeRename, newEntryPos); |
|
1250 |
|
1251 if(!IsRuggedFSys()) |
|
1252 FAT().FlushL(); |
|
1253 } |
|
1254 |
|
1255 //----------------------------------------------------------------------------------------- |
|
1256 |
|
1257 /** |
|
1258 Replace contents of the 'aNewName' with the contents of 'aOldName' |
|
1259 all trailing dots from the names will be removed |
|
1260 |
|
1261 @param aOldName existing object name |
|
1262 @param aNewName new object name |
|
1263 */ |
|
1264 void CFatMountCB::ReplaceL(const TDesC& aOldName,const TDesC& aNewName) |
|
1265 { |
|
1266 |
|
1267 __PRINT3(_L("CFatMountCB::ReplaceL, drv:%d, %S %S"), DriveNumber(), &aOldName, &aNewName); |
|
1268 |
|
1269 CheckStateConsistentL(); |
|
1270 CheckWritableL(); |
|
1271 |
|
1272 TEntryPos newEntryPos; |
|
1273 DoRenameOrReplaceL(RemoveTrailingDots(aOldName), RemoveTrailingDots(aNewName), EModeReplace, newEntryPos); |
|
1274 if(!IsRuggedFSys()) |
|
1275 FAT().FlushL(); |
|
1276 } |
|
1277 |
|
1278 //----------------------------------------------------------------------------------------- |
|
1279 |
|
1280 |
|
1281 /** |
|
1282 Try to find a directory entry by the given name and path. |
|
1283 This method _must_ leave if the entry is not found. See the caller. |
|
1284 |
|
1285 @param aName path to the directory object. all trailing dots from the name will be removed. |
|
1286 @param anEntry on return will contain the entry data |
|
1287 |
|
1288 @leave KErrPathNotFound if there is no path to the aName |
|
1289 KErrNotFound if the entry corresponding to the aName is not found |
|
1290 system-wide erorr code of media read failure. |
|
1291 */ |
|
1292 void CFatMountCB::EntryL(const TDesC& aName,TEntry& anEntry) const |
|
1293 { |
|
1294 __PRINT2(_L("CFatMountCB::EntryL, drv:%d, %S"), DriveNumber(), &aName); |
|
1295 |
|
1296 CheckStateConsistentL(); |
|
1297 |
|
1298 TEntryPos entryPos(RootIndicator(),0); |
|
1299 TFatDirEntry entry; |
|
1300 TPtr fileName(anEntry.iName.Des()); |
|
1301 |
|
1302 TPtrC fullName = RemoveTrailingDots(aName); |
|
1303 TInt namePos=fullName.LocateReverse(KPathDelimiter)+1; // There is always a path delimiter |
|
1304 TLeafDirData leafDir; |
|
1305 entryPos.iCluster=FindLeafDirL(fullName.Left(namePos), leafDir); |
|
1306 entryPos.iPos=0; |
|
1307 TEntryPos startPos; |
|
1308 TFatDirEntry startEntry; |
|
1309 |
|
1310 DoFindL(fullName.Mid(namePos),KEntryAttMaskSupported, |
|
1311 startPos,startEntry,entryPos,entry, |
|
1312 fileName,KErrNotFound, |
|
1313 NULL, |
|
1314 leafDir); |
|
1315 |
|
1316 |
|
1317 anEntry.iAtt=entry.Attributes(); |
|
1318 anEntry.iSize=entry.Size(); |
|
1319 anEntry.iModified=entry.Time(TimeOffset()); |
|
1320 |
|
1321 if (fileName.Length()==0) |
|
1322 { |
|
1323 TBuf8<0x20> dosName(DosNameFromStdFormat(entry.Name())); |
|
1324 LocaleUtils::ConvertToUnicodeL(fileName,dosName); |
|
1325 } |
|
1326 if ((TUint)anEntry.iSize>=sizeof(TCheckedUid)) |
|
1327 ReadUidL(StartCluster(entry),anEntry); |
|
1328 } |
|
1329 |
|
1330 //----------------------------------------------------------------------------------------- |
|
1331 |
|
1332 /** |
|
1333 Set directory entry details. |
|
1334 @param aName entry name; all trailing dots from the name will be removed |
|
1335 @param aTime entry modification time (and last access as well) |
|
1336 @param aSetAttMask entry attributes OR mask |
|
1337 @param aClearAttMask entry attributes AND mask |
|
1338 |
|
1339 */ |
|
1340 void CFatMountCB::SetEntryL(const TDesC& aName,const TTime& aTime,TUint aSetAttMask,TUint aClearAttMask) |
|
1341 { |
|
1342 __PRINT2(_L("CFatMountCB::SetEntryL, drv:%d, %S"), DriveNumber(), &aName); |
|
1343 |
|
1344 CheckStateConsistentL(); |
|
1345 CheckWritableL(); |
|
1346 |
|
1347 TEntryPos firstEntryPos(RootIndicator(),0); |
|
1348 TFatDirEntry firstEntry; |
|
1349 FindEntryStartL(RemoveTrailingDots(aName),KEntryAttMaskSupported,firstEntry,firstEntryPos); |
|
1350 MoveToDosEntryL(firstEntryPos,firstEntry); |
|
1351 TUint setAttMask=aSetAttMask&KEntryAttMaskSupported; |
|
1352 if (setAttMask|aClearAttMask) |
|
1353 { |
|
1354 TInt att=firstEntry.Attributes(); |
|
1355 att|=setAttMask; |
|
1356 att&=(~aClearAttMask); |
|
1357 firstEntry.SetAttributes(att); |
|
1358 } |
|
1359 if (aSetAttMask&KEntryAttModified) |
|
1360 { |
|
1361 firstEntry.SetTime(aTime,TimeOffset()); |
|
1362 } |
|
1363 WriteDirEntryL(firstEntryPos,firstEntry); |
|
1364 } |
|
1365 |
|
1366 //----------------------------------------------------------------------------------------- |
|
1367 |
|
1368 void CFatMountCB::DoCheckFatForLoopsL(TInt aCluster, TInt& aPreviousCluster, TInt& aChangePreviousCluster, TInt& aCount) const |
|
1369 // |
|
1370 // Check one fat cluster for loops. |
|
1371 // |
|
1372 { |
|
1373 |
|
1374 if (aCluster==aPreviousCluster) |
|
1375 User::Leave(KErrCorrupt); // Found loop |
|
1376 |
|
1377 aCount++; |
|
1378 if (aCount==aChangePreviousCluster) |
|
1379 { |
|
1380 aCount=0; |
|
1381 aChangePreviousCluster<<=1; |
|
1382 aPreviousCluster=aCluster; |
|
1383 } |
|
1384 } |
|
1385 |
|
1386 //----------------------------------------------------------------------------------------- |
|
1387 |
|
1388 void CFatMountCB::CheckFatForLoopsL(const TFatDirEntry& anEntry) const |
|
1389 // |
|
1390 // Check for loops |
|
1391 // |
|
1392 { |
|
1393 |
|
1394 TInt cluster=StartCluster(anEntry); |
|
1395 if (cluster==0 && anEntry.Size()==0) |
|
1396 return; |
|
1397 |
|
1398 TInt previousCluster=cluster; |
|
1399 TInt changePreviousCluster=1; |
|
1400 TInt count=0; |
|
1401 |
|
1402 |
|
1403 for(;;) |
|
1404 { |
|
1405 if ((TUint)cluster < KFatFirstSearchCluster || (!IsEndOfClusterCh(cluster) && (TUint)cluster>MaxClusterNumber())) |
|
1406 User::Leave(KErrCorrupt); |
|
1407 |
|
1408 if(!FAT().GetNextClusterL(cluster)) |
|
1409 break; |
|
1410 |
|
1411 DoCheckFatForLoopsL(cluster, previousCluster, changePreviousCluster, count); |
|
1412 } |
|
1413 |
|
1414 } |
|
1415 |
|
1416 //----------------------------------------------------------------------------------------- |
|
1417 |
|
1418 /** |
|
1419 Open/Create/Replace a file on the current mount. |
|
1420 |
|
1421 @param aName file name; all trailing dots from the name will be removed |
|
1422 @param aMode File open mode, See TFileMode |
|
1423 @param anOpen specifies action: open, create or replace the file |
|
1424 @param aFile pointer to the CFileCB object to populate |
|
1425 |
|
1426 */ |
|
1427 void CFatMountCB::FileOpenL(const TDesC& aName,TUint aMode,TFileOpen anOpen,CFileCB* aFile) |
|
1428 { |
|
1429 __PRINT3(_L("CFatMountCB::FileOpenL, drv:%d, mode:%d, name:%S"), DriveNumber(), anOpen, &aName); |
|
1430 |
|
1431 CheckStateConsistentL(); |
|
1432 |
|
1433 TPtrC fullName = RemoveTrailingDots(aName); //-- remove trailing dots from the name |
|
1434 |
|
1435 TFatDirEntry firstEntry; |
|
1436 TEntryPos firstEntryPos(RootIndicator(),0); |
|
1437 TInt nPos=fullName.LocateReverse(KPathDelimiter)+1; // There is always a path delimiter |
|
1438 TPtrC name(fullName.Mid(nPos)); |
|
1439 TInt ret = KErrNone; |
|
1440 |
|
1441 iFileCreationHelper.Close(); |
|
1442 if (anOpen == EFileCreate || anOpen == EFileReplace) |
|
1443 { |
|
1444 iFileCreationHelper.InitialiseL(name); |
|
1445 TRAP(ret,FindEntryStartL(fullName,KEntryAttMaskSupported,firstEntry,firstEntryPos,&iFileCreationHelper)); |
|
1446 } |
|
1447 else |
|
1448 { |
|
1449 TRAP(ret,FindEntryStartL(fullName,KEntryAttMaskSupported,firstEntry,firstEntryPos)); |
|
1450 } |
|
1451 |
|
1452 if (ret!=KErrNone && ret!=KErrNotFound) |
|
1453 User::Leave(ret); |
|
1454 |
|
1455 if (ret==KErrNone) |
|
1456 { |
|
1457 MoveToDosEntryL(firstEntryPos,firstEntry); |
|
1458 if ((firstEntry.Attributes()&KEntryAttDir) || (firstEntry.Attributes()&KEntryAttVolume)) |
|
1459 User::Leave(KErrAccessDenied); |
|
1460 if (anOpen==EFileCreate) |
|
1461 User::Leave(KErrAlreadyExists); |
|
1462 if ((firstEntry.Attributes()&KEntryAttReadOnly) && aMode&EFileWrite) |
|
1463 User::Leave(KErrAccessDenied); |
|
1464 if((aMode & EFileWrite) && (IsFileClamped(StartCluster(firstEntry))>0)) |
|
1465 User::Leave(KErrInUse); |
|
1466 CheckFatForLoopsL(firstEntry); |
|
1467 } |
|
1468 else |
|
1469 { |
|
1470 if (anOpen==EFileOpen) |
|
1471 User::Leave(KErrNotFound); |
|
1472 |
|
1473 //-- here we try to either create or replace file |
|
1474 CheckWritableL(); |
|
1475 |
|
1476 TLeafDirData leafDir; |
|
1477 |
|
1478 TInt numEntries = iFileCreationHelper.NumOfAddingEntries(); |
|
1479 TShortName shortName; |
|
1480 if (iFileCreationHelper.GetValidatedShortName(shortName) == KErrNotFound) |
|
1481 { |
|
1482 firstEntryPos.iCluster=FindLeafDirL(fullName.Left(nPos), leafDir); |
|
1483 GenerateShortNameL(firstEntryPos.iCluster,name,shortName,ETrue); |
|
1484 } |
|
1485 |
|
1486 if (iFileCreationHelper.IsNewEntryPosFound()) |
|
1487 { |
|
1488 firstEntryPos = iFileCreationHelper.EntryAddingPos(); |
|
1489 } |
|
1490 else |
|
1491 { |
|
1492 firstEntryPos.iCluster=FindLeafDirL(fullName.Left(nPos), leafDir); |
|
1493 firstEntryPos.iPos=0; |
|
1494 } |
|
1495 |
|
1496 AddDirEntryL(firstEntryPos,numEntries); |
|
1497 firstEntry.InitZ(); |
|
1498 firstEntry.SetName(shortName); |
|
1499 firstEntry.SetStartCluster(0); |
|
1500 |
|
1501 TTime now; |
|
1502 now.UniversalTime(); |
|
1503 firstEntry.SetCreateTime(now, TimeOffset() ); |
|
1504 |
|
1505 if (iFileCreationHelper.IsTrgNameLegalDosName()) |
|
1506 WriteDirEntryL(firstEntryPos,firstEntry); |
|
1507 else |
|
1508 WriteDirEntryL(firstEntryPos,firstEntry,name); |
|
1509 } |
|
1510 |
|
1511 CFatFileCB& file=(*((CFatFileCB*)aFile)); |
|
1512 file.SetL(firstEntry,(TShare)(aMode&KFileShareMask),firstEntryPos); |
|
1513 if (anOpen==EFileReplace && file.Size()) |
|
1514 { |
|
1515 file.SetSizeL(0); |
|
1516 file.SetSize(0); |
|
1517 } |
|
1518 if (file.IsSeekIndex()==EFalse) |
|
1519 file.CreateSeekIndex(); |
|
1520 if (anOpen==EFileReplace || anOpen==EFileCreate) |
|
1521 file.SetArchiveAttribute(); |
|
1522 |
|
1523 if(!IsRuggedFSys()) |
|
1524 FAT().FlushL(); |
|
1525 |
|
1526 iFileCreationHelper.Close(); |
|
1527 } |
|
1528 |
|
1529 //----------------------------------------------------------------------------------------- |
|
1530 |
|
1531 |
|
1532 /** |
|
1533 Open a directory on the current mount. |
|
1534 |
|
1535 @param aName path to the object in the directory we want to open; all trailing dots from the name will be removed |
|
1536 @param aDir dir. CB to be filled in. |
|
1537 |
|
1538 If there is no such a path, this method must leave with KErrPathNotFound |
|
1539 |
|
1540 @leave KErrPathNotFound if thereis no such path |
|
1541 @leave error code on media read fault |
|
1542 */ |
|
1543 void CFatMountCB::DirOpenL(const TDesC& aName,CDirCB* aDir) |
|
1544 { |
|
1545 __PRINT2(_L("CFatMountCB::DirOpenL, drv:%d, %S"), DriveNumber(), &aName); |
|
1546 |
|
1547 CheckStateConsistentL(); |
|
1548 |
|
1549 const TPtrC dirName = RemoveTrailingDots(aName); //-- remove trailing dots from the name |
|
1550 |
|
1551 TInt namePos=dirName.LocateReverse(KPathDelimiter); |
|
1552 |
|
1553 TFatDirEntry dosEntry; |
|
1554 TEntryPos dosEntryPos(RootIndicator(),0); |
|
1555 if (namePos==0) |
|
1556 InitializeRootEntry(dosEntry); |
|
1557 else |
|
1558 { |
|
1559 TPtrC dirPath=dirName.Left(namePos); |
|
1560 TInt dirPos=dirPath.LocateReverse(KPathDelimiter)+1; |
|
1561 TLeafDirData leafDir; |
|
1562 dosEntryPos.iCluster=FindLeafDirL(dirPath.Left(dirPos), leafDir); // Find directory before leaf |
|
1563 dosEntryPos.iPos=0; |
|
1564 |
|
1565 TFileName fileName; |
|
1566 TEntryPos startPos; |
|
1567 TFatDirEntry startEntry; |
|
1568 DoFindL(dirPath.Mid(dirPos), |
|
1569 KEntryAttMatchMask|KEntryAttMatchExclusive, |
|
1570 startPos, startEntry, dosEntryPos, dosEntry, |
|
1571 fileName, KErrPathNotFound, |
|
1572 NULL, |
|
1573 leafDir); |
|
1574 |
|
1575 |
|
1576 } |
|
1577 |
|
1578 TPtrC matchName(dirName.Mid(namePos+1)); |
|
1579 if (matchName.Length()==0) |
|
1580 matchName.Set(_L("*")); |
|
1581 |
|
1582 ((CFatDirCB*)aDir)->SetDirL(dosEntry,matchName); |
|
1583 |
|
1584 } |
|
1585 |
|
1586 //----------------------------------------------------------------------------------------- |
|
1587 |
|
1588 TBool CFatMountCB::IsDirectoryEmptyL(TInt aCluster) |
|
1589 // |
|
1590 // Check aCluster contains no directory entries other than . and .. |
|
1591 // |
|
1592 { |
|
1593 |
|
1594 __PRINT(_L("CFatMountCB::IsDirectoryEmptyL")); |
|
1595 TEntryPos dirEntryPos(aCluster,0); |
|
1596 TFatDirEntry dirEntry; |
|
1597 FOREVER |
|
1598 { |
|
1599 ReadDirEntryL(dirEntryPos,dirEntry); |
|
1600 MoveToDosEntryL(dirEntryPos,dirEntry); |
|
1601 if (dirEntry.IsParentDirectory() || dirEntry.IsCurrentDirectory()) |
|
1602 goto LoopEnd; |
|
1603 if (dirEntry.IsEndOfDirectory()) |
|
1604 return ETrue; |
|
1605 if (IsRootDir(dirEntryPos)&&(dirEntryPos.iPos+StartOfRootDirInBytes()==RootDirEnd())) |
|
1606 return ETrue; // Root Directory has no end of directory marker |
|
1607 if (!dirEntry.IsErased()) |
|
1608 return EFalse; |
|
1609 LoopEnd: |
|
1610 MoveToNextEntryL(dirEntryPos); |
|
1611 } |
|
1612 } |
|
1613 |
|
1614 //----------------------------------------------------------------------------------------- |
|
1615 |
|
1616 /** |
|
1617 Overwrite as many contiguous file clusters as possible. |
|
1618 */ |
|
1619 void CFatMountCB::DoWriteToClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2& aMessage,TInt anOffset, TInt aLastcluster, TInt &aBadcluster, TInt &aGoodcluster) |
|
1620 { |
|
1621 |
|
1622 __PRINT(_L("CFatMountCB::DoWriteToClusterListL")); |
|
1623 __ASSERT_ALWAYS(aPos.Cluster()>=KFatFirstSearchCluster,User::Leave(KErrCorrupt)); |
|
1624 |
|
1625 TInt endCluster=0; |
|
1626 |
|
1627 const TInt clusterRelativePos=ClusterRelativePos(aPos.iPos); |
|
1628 const TInt maxClusters=((aLength+clusterRelativePos-1)>>ClusterSizeLog2())+1; |
|
1629 const TInt clusterListLen=FAT().CountContiguousClustersL(aPos.iCluster,endCluster,maxClusters); |
|
1630 const TInt writeLength=Min(aLength,(clusterListLen<<ClusterSizeLog2())-clusterRelativePos); |
|
1631 TInt64 dataStart=FAT().DataPositionInBytes(aPos.iCluster)+clusterRelativePos; |
|
1632 |
|
1633 TRAPD(r, iRawDisk->WriteL(dataStart,writeLength,aSrc,aMessage,anOffset)); |
|
1634 |
|
1635 if(r == KErrNone) // Write succeded |
|
1636 { |
|
1637 aPos.iPos+=writeLength; |
|
1638 aPos.iCluster=endCluster; |
|
1639 return; |
|
1640 } |
|
1641 |
|
1642 if(r != KErrCorrupt) // failure not due to corruption so propogate up |
|
1643 User::Leave(r); |
|
1644 |
|
1645 TErrorInfoBuf errinf; |
|
1646 r = iRawDisk->GetLastErrorInfo(errinf); |
|
1647 |
|
1648 if(r == KErrNone && errinf().iReasonCode == TErrorInfo::EBadSector) // GetLastErrorInfo succeded and Last Error was caused by bad sector |
|
1649 { |
|
1650 |
|
1651 const TInt badcluster = (TInt)(((dataStart + errinf().iErrorPos) - ClusterBasePosition())>>ClusterSizeLog2())+KFatFirstSearchCluster; |
|
1652 TInt goodcluster = FAT().AllocateSingleClusterL(badcluster); |
|
1653 |
|
1654 //Calculate cluster number to check whether this write started at the beginning of new cluster or middle of previous cluster. |
|
1655 TInt cluster = aPos.iCluster; |
|
1656 if ( (aPos.iPos) && ((aPos.iPos)==((aPos.iPos >> ClusterSizeLog2())<<ClusterSizeLog2()))) |
|
1657 cluster--; |
|
1658 |
|
1659 if((aPos.iPos != 0) && (badcluster == aPos.iCluster) && (aLastcluster == 0) && (aPos.iCluster == cluster)) |
|
1660 { //Copy the contents already present in this cluster to new cluster allocated. |
|
1661 const TInt sizeToRead = aPos.iPos - ((aPos.iPos >> ClusterSizeLog2()) << ClusterSizeLog2()); |
|
1662 dataStart = FAT().DataPositionInBytes(aPos.iCluster) + ClusterRelativePos((aPos.iPos - sizeToRead)); |
|
1663 |
|
1664 |
|
1665 //-- Allocate the buffer required to copy the contents from bad cluster |
|
1666 RBuf8 clustBuf; |
|
1667 CleanupClosePushL(clustBuf); |
|
1668 if(clustBuf.CreateMax(sizeToRead) != KErrNone) |
|
1669 { |
|
1670 FAT().FreeClusterListL(goodcluster); |
|
1671 User::Leave(KErrNoMemory); |
|
1672 } |
|
1673 |
|
1674 r = LocalDrive()->Read(dataStart, sizeToRead, clustBuf); //Read the contents into buffer |
|
1675 if(r != KErrNone) //If read fails dont do anything not even marking bad cluster. |
|
1676 { |
|
1677 FAT().FreeClusterListL(goodcluster); |
|
1678 User::Leave(r); |
|
1679 } |
|
1680 |
|
1681 //Copy the bad and good cluster,required to adjust the start cluster number. |
|
1682 if(aBadcluster == 0) |
|
1683 aBadcluster = badcluster; |
|
1684 |
|
1685 aGoodcluster = goodcluster; |
|
1686 |
|
1687 FOREVER |
|
1688 { |
|
1689 //Calculate and copy the contents to new cluster. |
|
1690 aPos.iCluster = goodcluster; |
|
1691 dataStart = FAT().DataPositionInBytes(aPos.iCluster) + ClusterRelativePos(aPos.iPos - sizeToRead); |
|
1692 |
|
1693 r = LocalDrive()->Write(dataStart, clustBuf); |
|
1694 if(r == KErrNone) |
|
1695 { // Copied contents to new cluster so fix up the chain and mark the cluster as bad. |
|
1696 FAT().WriteL(goodcluster, FAT().ReadL(badcluster)); |
|
1697 FAT().MarkAsBadClusterL(badcluster); |
|
1698 aGoodcluster = goodcluster; |
|
1699 CleanupStack::PopAndDestroy(&clustBuf); //-- deallocate a cluster buffer |
|
1700 return; |
|
1701 } |
|
1702 else if(r == KErrCorrupt) |
|
1703 { |
|
1704 r = LocalDrive()->GetLastErrorInfo(errinf); |
|
1705 if(r == KErrNone && errinf().iReasonCode == TErrorInfo::EBadSector) |
|
1706 { //Allocate new cluster and adjust the cluster list. |
|
1707 goodcluster = FAT().AllocateSingleClusterL(aPos.iCluster); |
|
1708 FAT().MarkAsBadClusterL(aPos.iCluster); |
|
1709 continue; |
|
1710 } |
|
1711 r = KErrCorrupt; |
|
1712 } |
|
1713 //Not able to write successfully so dont alter the original list. |
|
1714 aBadcluster = aGoodcluster = 0; |
|
1715 FAT().FreeClusterListL(goodcluster); |
|
1716 User::Leave(r); |
|
1717 } |
|
1718 |
|
1719 }//if((aPos.iPos != 0) && (badcluster == aPos.iCluster) && (aLastcluster == 0) && (aPos.iCluster == cluster)) |
|
1720 |
|
1721 if((badcluster == aPos.iCluster) && (aLastcluster == 0)) //bad cluster at beginning of original clusterlist |
|
1722 { |
|
1723 // return bad and good clusters for CFatFileCB to fix up |
|
1724 FAT().WriteL(goodcluster, FAT().ReadL(badcluster)); |
|
1725 aBadcluster = badcluster; |
|
1726 aGoodcluster = goodcluster; |
|
1727 aPos.iCluster = goodcluster; |
|
1728 } |
|
1729 else //fix up chain |
|
1730 { |
|
1731 FAT().WriteL(goodcluster, FAT().ReadL(badcluster)); |
|
1732 if(badcluster > aPos.iCluster) //bad cluster not first in this contiguous list |
|
1733 FAT().WriteL(badcluster-1, goodcluster); |
|
1734 else //first cluster of this contigous list bad so update last cluster of previous contiguous list |
|
1735 FAT().WriteL(aLastcluster, goodcluster); |
|
1736 } |
|
1737 |
|
1738 FAT().MarkAsBadClusterL(badcluster); |
|
1739 |
|
1740 |
|
1741 return; |
|
1742 } |
|
1743 User::Leave(KErrCorrupt); |
|
1744 } |
|
1745 |
|
1746 //----------------------------------------------------------------------------------------- |
|
1747 |
|
1748 void CFatMountCB::WriteToClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2& aMessage,TInt anOffset, TInt &aBadcluster, TInt& aGoodcluster) |
|
1749 // |
|
1750 // Overwrite cluster list. |
|
1751 // |
|
1752 { |
|
1753 |
|
1754 __PRINT(_L("CFatMountCB::WriteToClusterListL")); |
|
1755 __ASSERT_ALWAYS(aPos.Cluster()>=KFatFirstSearchCluster,User::Leave(KErrCorrupt)); |
|
1756 |
|
1757 const TUint startPos=aPos.iPos; |
|
1758 const TUint temp=startPos>>ClusterSizeLog2(); |
|
1759 const TUint length = (TUint)aLength; |
|
1760 |
|
1761 if ( (startPos) && ((startPos)==(temp<<ClusterSizeLog2())) ) |
|
1762 { |
|
1763 __ASSERT_ALWAYS(FAT().GetNextClusterL(aPos.iCluster),User::Leave(KErrCorrupt)); |
|
1764 } |
|
1765 |
|
1766 TUint offset=0; |
|
1767 TInt previouscluster=0; |
|
1768 FOREVER |
|
1769 { |
|
1770 DoWriteToClusterListL(aPos,length-offset,aSrc,aMessage,anOffset+offset, previouscluster, aBadcluster, aGoodcluster); |
|
1771 if (offset == (aPos.iPos-startPos)) |
|
1772 continue; |
|
1773 offset=aPos.iPos-startPos; |
|
1774 __ASSERT_ALWAYS(aPos.iPos>startPos,User::Leave(KErrCorrupt)); |
|
1775 previouscluster=aPos.iCluster; |
|
1776 if (offset<length) |
|
1777 {__ASSERT_ALWAYS(FAT().GetNextClusterL(aPos.iCluster),User::Leave(KErrCorrupt));} |
|
1778 if (offset>=length) |
|
1779 return; |
|
1780 } |
|
1781 } |
|
1782 |
|
1783 //----------------------------------------------------------------------------------------- |
|
1784 |
|
1785 void CFatMountCB::DoReadFromClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2& aMessage,TInt anOffset) const |
|
1786 // |
|
1787 // Read from as many contiguous file clusters as possible |
|
1788 // |
|
1789 { |
|
1790 |
|
1791 __PRINT(_L("CFatMountCB::DoReadFromClusterListL")); |
|
1792 |
|
1793 TInt endCluster=0; |
|
1794 |
|
1795 const TInt clusterRelativePos=ClusterRelativePos(aPos.iPos); |
|
1796 const TInt maxClusters=((aLength+clusterRelativePos-1)>>ClusterSizeLog2())+1; |
|
1797 const TInt clusterListLen=FAT().CountContiguousClustersL(aPos.iCluster,endCluster,maxClusters); |
|
1798 const TInt readLength=Min(aLength,(clusterListLen<<ClusterSizeLog2())-clusterRelativePos); |
|
1799 const TInt64 dataStart=FAT().DataPositionInBytes(aPos.iCluster)+clusterRelativePos; |
|
1800 |
|
1801 TRAPD(r, iRawDisk->ReadL(dataStart,readLength,aTrg,aMessage,anOffset)); |
|
1802 |
|
1803 if(r == KErrNone) // Read succeded |
|
1804 { |
|
1805 aPos.iPos+=readLength; |
|
1806 aPos.iCluster=endCluster; |
|
1807 return; |
|
1808 } |
|
1809 if(r != KErrCorrupt) // failure not due to corruption so propogate up |
|
1810 User::Leave(r); |
|
1811 |
|
1812 TErrorInfoBuf errinf; |
|
1813 r = iRawDisk->GetLastErrorInfo(errinf); |
|
1814 |
|
1815 if(r == KErrNone && errinf().iReasonCode == TErrorInfo::EBadSector) // GetLastErrorInfo succeded and Last Error was caused by bad sector |
|
1816 { |
|
1817 TInt badcluster = (TInt)(((dataStart + errinf().iErrorPos) - ClusterBasePosition())>>ClusterSizeLog2())+KFatFirstSearchCluster; |
|
1818 FAT().MarkAsBadClusterL(badcluster); |
|
1819 } |
|
1820 |
|
1821 User::Leave(KErrCorrupt); |
|
1822 } |
|
1823 |
|
1824 //----------------------------------------------------------------------------------------- |
|
1825 |
|
1826 void CFatMountCB::ReadFromClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2& aMessage,TInt anOffset) const |
|
1827 // |
|
1828 // Read from cluster list |
|
1829 // |
|
1830 { |
|
1831 |
|
1832 __PRINT(_L("CFatMountCB::ReadFromClusterListL")); |
|
1833 __ASSERT_ALWAYS(aPos.Cluster()>=KFatFirstSearchCluster,User::Leave(KErrCorrupt)); |
|
1834 |
|
1835 const TInt startPos=aPos.iPos; |
|
1836 const TInt temp=startPos>>ClusterSizeLog2(); |
|
1837 |
|
1838 if ( (startPos) && ((startPos)==(temp<<ClusterSizeLog2())) ) |
|
1839 { |
|
1840 __ASSERT_ALWAYS(FAT().GetNextClusterL(aPos.iCluster),User::Leave(KErrCorrupt)); |
|
1841 } |
|
1842 |
|
1843 TInt offset=0; |
|
1844 FOREVER |
|
1845 { |
|
1846 DoReadFromClusterListL(aPos,aLength-offset,aTrg,aMessage,anOffset+offset); |
|
1847 offset=aPos.iPos-startPos; |
|
1848 if ((offset<aLength)) |
|
1849 { |
|
1850 __ASSERT_ALWAYS(FAT().GetNextClusterL(aPos.iCluster),User::Leave(KErrCorrupt)); |
|
1851 } |
|
1852 if (offset>=aLength) |
|
1853 return; |
|
1854 } |
|
1855 } |
|
1856 |
|
1857 //----------------------------------------------------------------------------------------- |
|
1858 |
|
1859 TInt CFatMountCB::FindLeafDirL(const TDesC& aName, TLeafDirData& aLeafDir) const |
|
1860 // |
|
1861 // Navigate the path to find the leaf directory. |
|
1862 // Returns the startcluster of data for the directory found. |
|
1863 // |
|
1864 { |
|
1865 |
|
1866 __PRINT(_L("CFatMountCB::FindLeafDirL")); |
|
1867 |
|
1868 TLex lex(aName); |
|
1869 TInt r; |
|
1870 TEntryPos entryPos(RootIndicator(),0); |
|
1871 |
|
1872 if (iLeafDirCache == NULL) |
|
1873 { |
|
1874 TInt leaflen=(iLastLeafDir) ? iLastLeafDir->Length() : 0; |
|
1875 TInt namelen=aName.Length(); |
|
1876 if (leaflen>1 && namelen>=leaflen && *iLastLeafDir==aName.Left(leaflen)) |
|
1877 { |
|
1878 if (leaflen==namelen) |
|
1879 return(iLastLeafDirCluster); |
|
1880 lex.Inc(leaflen-1); |
|
1881 entryPos.iCluster=iLastLeafDirCluster; |
|
1882 } |
|
1883 } |
|
1884 else |
|
1885 { |
|
1886 // Skip root directory |
|
1887 if (iLeafDirCache->CacheCount() > 0 && aName.Length() > 1) |
|
1888 { |
|
1889 TInt err = iLeafDirCache->FindInCache(aName, aLeafDir); |
|
1890 if (err == KErrNone) |
|
1891 { |
|
1892 ASSERT(aLeafDir.iClusterNum > 0); |
|
1893 return aLeafDir.iClusterNum; |
|
1894 } |
|
1895 else if (err != KErrNotFound) |
|
1896 { |
|
1897 User::LeaveIfError(err); |
|
1898 } |
|
1899 } |
|
1900 } |
|
1901 |
|
1902 FOREVER |
|
1903 { |
|
1904 lex.Inc(); // Skip path delimiter |
|
1905 lex.Mark(); |
|
1906 r=lex.Remainder().Locate(KPathDelimiter); |
|
1907 if (r==KErrNotFound) |
|
1908 r=lex.Remainder().Length(); |
|
1909 if (r==0) // End of the path |
|
1910 break; |
|
1911 lex.Inc(r); // Set the token length |
|
1912 TFatDirEntry entry; |
|
1913 |
|
1914 TFileName fileName; |
|
1915 TEntryPos startPos; |
|
1916 TFatDirEntry startEntry; |
|
1917 DoFindL(lex.MarkedToken(), |
|
1918 KEntryAttMatchMask|KEntryAttMatchExclusive, |
|
1919 startPos, startEntry, entryPos, entry, |
|
1920 fileName, KErrPathNotFound, |
|
1921 NULL, |
|
1922 aLeafDir); |
|
1923 |
|
1924 |
|
1925 entryPos.iCluster=StartCluster(entry); |
|
1926 entryPos.iPos=0; |
|
1927 } |
|
1928 |
|
1929 if (iLeafDirCache == NULL) |
|
1930 { |
|
1931 AllocBufferL(((CFatMountCB*)this)->iLastLeafDir,aName); |
|
1932 ((CFatMountCB*)this)->iLastLeafDirCluster=entryPos.iCluster; |
|
1933 } |
|
1934 else |
|
1935 { |
|
1936 if (aName.Length() > 1) |
|
1937 { |
|
1938 aLeafDir = TLeafDirData(entryPos.iCluster); |
|
1939 iLeafDirCache->AddToCacheL(aName, aLeafDir); |
|
1940 } |
|
1941 } |
|
1942 |
|
1943 return entryPos.iCluster; |
|
1944 } |
|
1945 |
|
1946 //----------------------------------------------------------------------------------------- |
|
1947 |
|
1948 /** |
|
1949 Search for a specified name winthin directory cache |
|
1950 Works similary to TBool CFatMountCB::DoFindL() |
|
1951 |
|
1952 @param anAtt attributes of the object to find |
|
1953 @param aStartEntryPos on return in case of VFAT entry will contain start position of the VFAT dir. entry |
|
1954 @param aStartEntry on return will contain first VFAT dir entry |
|
1955 @param aDosEntryPos the search will start from this position of dir entry, on return it will contain result DOS entry position, last one for VFAT case |
|
1956 @param aDosEntry on return will contain DOS dir entry (the last one for VFAT case) |
|
1957 @param aFileName in the case of VFAT entry and on success here will be returned a long filename |
|
1958 @param aAuxParam some parameters package |
|
1959 @param aFileCreationHelper a helper package for file creations |
|
1960 |
|
1961 @return ETrue if the specified name is found in the cache. In this case aStartEntryPos, aStartEntry, aDosEntryPos, aDosEntry, aFileName will contain valid values |
|
1962 */ |
|
1963 TBool CFatMountCB::DoRummageDirCacheL(const TUint anAtt, TEntryPos& aStartEntryPos, |
|
1964 TFatDirEntry& aStartEntry, TEntryPos& aDosEntryPos, |
|
1965 TFatDirEntry& aDosEntry, TDes& aFileName, |
|
1966 const TFindHelper& aAuxParam, |
|
1967 XFileCreationHelper* aFileCreationHelper, |
|
1968 const TLeafDirData& aLeafDir) const |
|
1969 { |
|
1970 TBool bCacheMatchFound = EFalse; |
|
1971 |
|
1972 //-- get an interface to the Dir. cache |
|
1973 MWTCacheInterface* pDirCache = iRawDisk->DirCacheInterface(); |
|
1974 ASSERT(pDirCache); |
|
1975 if(!pDirCache) |
|
1976 return EFalse; |
|
1977 |
|
1978 //-- save original values in order to restore them in the case of negative search results |
|
1979 TEntryPos StartEntryPos1(aStartEntryPos); |
|
1980 TEntryPos DosEntryPos1(aDosEntryPos); |
|
1981 TFatDirEntry StartEntry1(aStartEntry); |
|
1982 TFatDirEntry DosEntry1(aDosEntry); |
|
1983 |
|
1984 TInt64 nCachedLinPos; |
|
1985 |
|
1986 const TUint32 clSize = 1 << ClusterSizeLog2(); //-- media cluster size |
|
1987 const TUint32 cacheSz = pDirCache->CacheSizeInBytes(); //-- cache size in bytes |
|
1988 const TUint32 maxDirEntries = cacheSz >> KSizeOfFatDirEntryLog2; //-- maximal number of dir entries that can be in the cache |
|
1989 |
|
1990 const TUint pageSzLog2 = pDirCache->PageSizeInBytesLog2(); |
|
1991 TBool ScanMRUPageFirst = EFalse; |
|
1992 TBool MRUPageScanned = EFalse; |
|
1993 |
|
1994 // if MRU pos is availale, start with MRU page |
|
1995 if (aLeafDir.iMRUPos.Cluster()) |
|
1996 { |
|
1997 ScanMRUPageFirst = ETrue; |
|
1998 DosEntryPos1 = aLeafDir.iMRUPos; |
|
1999 } |
|
2000 |
|
2001 TInt numFound = 0; |
|
2002 TEntryPos startPos = DosEntryPos1; |
|
2003 TInt clusterNum = DosEntryPos1.iCluster; |
|
2004 |
|
2005 for(TUint32 entryCnt=0; entryCnt < maxDirEntries; ++entryCnt) |
|
2006 {//-- walk through directory cluster list. The loop is limited by maximal number of dir entries |
|
2007 //-- that can be cached. Helps to avoid problems with infinite (looped) directories |
|
2008 |
|
2009 if (IsEndOfClusterCh(DosEntryPos1.iCluster)) |
|
2010 { |
|
2011 // refer back to the last stored cluster position |
|
2012 // note aFileCreationHelper may not be initialised for file opening operations |
|
2013 if (aFileCreationHelper && aFileCreationHelper->IsInitialised() && clusterNum != DosEntryPos1.iCluster) |
|
2014 { |
|
2015 TEntryPos dummyPos(clusterNum, clSize - KSizeOfFatDirEntry); |
|
2016 aFileCreationHelper->SetEntryAddingPos(dummyPos); |
|
2017 aFileCreationHelper->SetIsNewEntryPosFound(ETrue); |
|
2018 } |
|
2019 |
|
2020 if (ScanMRUPageFirst && !MRUPageScanned) |
|
2021 { |
|
2022 DosEntryPos1 = aDosEntryPos; |
|
2023 MRUPageScanned = ETrue; |
|
2024 continue; |
|
2025 } |
|
2026 break; //-- this was the last cluster in this directory |
|
2027 } |
|
2028 |
|
2029 const TUint32 pageStartPos = CalculatePageOffsetInCluster(DosEntryPos1.iPos, pageSzLog2); |
|
2030 DosEntryPos1.iPos = pageStartPos; |
|
2031 TBool PassedPageBoundary = EFalse; |
|
2032 |
|
2033 const TInt64 entryLinPos = MakeLinAddrL(DosEntryPos1); //-- linear media position of the cluster for this directory |
|
2034 const TUint32 cachePageSz = pDirCache->PosCached(entryLinPos, nCachedLinPos); //-- indicates if entryLinPos is cached |
|
2035 if(cachePageSz) |
|
2036 {//-- current page is in the directory cache |
|
2037 //__PRINT2(_L("#-!! CFatMountCB::DoRummageDirCacheL() Searching cl:%d, lin Pos:%X"),DosEntryPos1.iCluster,(TUint32)entryLinPos); |
|
2038 |
|
2039 //-- search to the end of the cached page. |
|
2040 // Note GetDirEntry() will read data beyond cache page boundary |
|
2041 const TUint32 nEntries = (1 << pageSzLog2) >> KSizeOfFatDirEntryLog2; |
|
2042 |
|
2043 TInt nErr; |
|
2044 //-- extract dir entries from the cached page and see if they match given name (aName) |
|
2045 /// until it reaches the next page |
|
2046 for(;;) |
|
2047 { |
|
2048 StartEntryPos1 = DosEntryPos1; |
|
2049 TInt clSave = DosEntryPos1.iCluster; //-- need to save current cluster number because GetDirEntry() & MoveToNextEntryL() can change it |
|
2050 |
|
2051 //-- get directory entry from the cache. We know that the DosEntryPos1 is cached. |
|
2052 nErr = GetDirEntry(DosEntryPos1, DosEntry1, StartEntry1, aFileName); |
|
2053 if(nErr != KErrNone) |
|
2054 break; |
|
2055 |
|
2056 if(DosEntry1.IsEndOfDirectory()) |
|
2057 { |
|
2058 if (aFileCreationHelper && aFileCreationHelper->IsInitialised() && !aFileCreationHelper->IsNewEntryPosFound()) |
|
2059 { |
|
2060 // note it is impossible to be at the end of the cluster chain here. |
|
2061 aFileCreationHelper->SetEntryAddingPos(DosEntryPos1); |
|
2062 aFileCreationHelper->SetIsNewEntryPosFound(ETrue); |
|
2063 } |
|
2064 |
|
2065 if (ScanMRUPageFirst && !MRUPageScanned) |
|
2066 { |
|
2067 break; |
|
2068 } |
|
2069 |
|
2070 // if (!ScanMRUPageFirst || ScanMRUPageFirst && MRUPageScanned) |
|
2071 goto Exit; //-- this was the last entry in this directory, no reason to look further |
|
2072 } |
|
2073 |
|
2074 if (aFileCreationHelper && aFileCreationHelper->IsInitialised() && !aFileCreationHelper->IsNewEntryPosFound()) |
|
2075 { |
|
2076 if (!DosEntry1.IsErased() && !DosEntry1.IsGarbage()) |
|
2077 { |
|
2078 numFound = 0; |
|
2079 } |
|
2080 else |
|
2081 { |
|
2082 if (numFound == 0) |
|
2083 { |
|
2084 startPos = DosEntryPos1; |
|
2085 } |
|
2086 numFound++; |
|
2087 if (numFound == aFileCreationHelper->NumOfAddingEntries()) |
|
2088 { |
|
2089 aFileCreationHelper->SetEntryAddingPos(startPos); |
|
2090 aFileCreationHelper->SetIsNewEntryPosFound(ETrue); |
|
2091 } |
|
2092 } |
|
2093 } |
|
2094 if(MatchEntryAtt(DosEntry1.Attributes(),anAtt)) |
|
2095 {//-- FAT or VFAT dir entry is extracted and attributes match. Compare names then. |
|
2096 |
|
2097 if(StartEntry1.IsVFatEntry()) |
|
2098 {//-- extracted entry is VFAT one, name can be in UNICODE |
|
2099 |
|
2100 // we only check short name candidates for long file names with VFAT entries, |
|
2101 // if it is a valid dos name, it will be checked by default |
|
2102 // note here target name is always fully specified |
|
2103 if (aFileCreationHelper && aFileCreationHelper->IsInitialised()) |
|
2104 { |
|
2105 aFileCreationHelper->CheckShortNameCandidates(DosEntry1.Name().Ptr()); |
|
2106 } |
|
2107 |
|
2108 TPtrC ptrAssembledName = RemoveTrailingDots(aFileName); |
|
2109 |
|
2110 if(ptrAssembledName.MatchF(aAuxParam.iTargetName) != KErrNotFound) |
|
2111 {//-- found match in cache |
|
2112 bCacheMatchFound = ETrue; |
|
2113 goto Exit; |
|
2114 } |
|
2115 else if(aAuxParam.TrgtNameIsLegalDos()) |
|
2116 { |
|
2117 if(aAuxParam.MatchDosEntryName(DosEntry1.Name().Ptr())) |
|
2118 { |
|
2119 bCacheMatchFound = ETrue; |
|
2120 goto Exit; |
|
2121 } |
|
2122 } |
|
2123 }//if(StartEntry1.IsVFatEntry()) |
|
2124 else if(aAuxParam.TrgtNameIsLegalDos()) |
|
2125 {//-- this is an old DOS FAT entry |
|
2126 |
|
2127 if(aAuxParam.MatchDosEntryName(DosEntry1.Name().Ptr())) |
|
2128 { |
|
2129 //-- Here is the trick that helps with the situation when VFAT entry is split into 2 halves |
|
2130 //-- between 2 clusters (or/and cache pages). I.e. 1st part of this long entry belongs to one cluster and even more might not be cached, |
|
2131 //-- While the rest of the entry, DOS part of it is the 1st entry in the cluster and cached. |
|
2132 //-- In this case if we search for short file name, we find it, but the aStartEntryPos will be incorrect, which leads to the directory corruption. |
|
2133 //-- The simple and quick solution - discard 1st DOS entry and return to old search. It shall be quite rare. |
|
2134 if(StartEntryPos1.iPos == 0) |
|
2135 {//-- this is the 1st FAT entry in the cluster. Discard it, see comments above. |
|
2136 __PRINT(_L("#------ CFatMountCB::DoRummageDirCacheL() discarding FAT Entry!!")); |
|
2137 goto Exit; |
|
2138 } |
|
2139 |
|
2140 bCacheMatchFound = ETrue; |
|
2141 goto Exit; |
|
2142 } |
|
2143 } |
|
2144 |
|
2145 }//if(bGotEntry && MatchEntryAtt(DosEntry1.Attributes(),anAtt)) |
|
2146 |
|
2147 // check boundaries after GetDirEntry() |
|
2148 // if we have cross the cluster boundary, break the for loop |
|
2149 if(DosEntryPos1.iCluster != clSave) |
|
2150 {//-- GetDirEntry() has decided to move to the next cluster. |
|
2151 DosEntryPos1.iCluster = clSave; |
|
2152 break; |
|
2153 } |
|
2154 |
|
2155 // if we are still in the same cluster, check the page boundary by |
|
2156 /// exam how many entries we have scanned within the cluster |
|
2157 const TUint entriesLooked = ((DosEntryPos1.iPos + KSizeOfFatDirEntry)- pageStartPos) >> KSizeOfFatDirEntryLog2; |
|
2158 if(entriesLooked > nEntries) |
|
2159 { |
|
2160 PassedPageBoundary = ETrue; |
|
2161 break; |
|
2162 } |
|
2163 |
|
2164 |
|
2165 // move to next entry before scanning next file |
|
2166 TRAP(nErr,MoveToNextEntryL(DosEntryPos1)); |
|
2167 if(nErr != KErrNone) |
|
2168 goto Exit; |
|
2169 |
|
2170 // check boundaries after MoveToNextEntryL() |
|
2171 if(DosEntryPos1.iCluster != clSave) |
|
2172 { |
|
2173 DosEntryPos1.iCluster = clSave; |
|
2174 break; |
|
2175 } |
|
2176 |
|
2177 if (entriesLooked + 1 > nEntries) |
|
2178 { |
|
2179 PassedPageBoundary = ETrue; |
|
2180 break; |
|
2181 } |
|
2182 |
|
2183 } //for(;;) |
|
2184 |
|
2185 } //if(iRawDisk->PosCached(...)) |
|
2186 |
|
2187 // scanning did not happen because the page is not cached, |
|
2188 // or |
|
2189 // scanning finished in last page and file is not found |
|
2190 |
|
2191 // if MRU page is not cached or |
|
2192 // we scan MRU page first and it is not scanned yet, then this must be the MRU page, |
|
2193 // we now start to scan from the beginning |
|
2194 if (ScanMRUPageFirst && !MRUPageScanned) |
|
2195 { |
|
2196 MRUPageScanned = ETrue; |
|
2197 DosEntryPos1 = aDosEntryPos; |
|
2198 DosEntryPos1.iPos = 0; |
|
2199 continue; |
|
2200 } |
|
2201 |
|
2202 // if we just finished scanning a page and still in the same cluster, then we crossed page |
|
2203 // boundary, continue with next page. |
|
2204 // note: although we are in the 'next page' already, this page might not be cached, so we need to |
|
2205 // check it via pDirCache->PosCached(entryLinPos, nCachedLinPos) and scan it properly. |
|
2206 if (PassedPageBoundary) |
|
2207 { |
|
2208 DosEntryPos1.iPos = CalculatePageOffsetInCluster(DosEntryPos1.iPos, pageSzLog2); |
|
2209 PassedPageBoundary = EFalse; |
|
2210 continue; |
|
2211 } |
|
2212 |
|
2213 //-- try to move to the next cluster of the directory file |
|
2214 |
|
2215 if(DosEntryPos1.Cluster() < KFatFirstSearchCluster) //-- small trick to get rid of TRAPping GetNextClusterL() |
|
2216 break; |
|
2217 |
|
2218 // record previous cluster number before move on |
|
2219 clusterNum = DosEntryPos1.iCluster; |
|
2220 |
|
2221 if(! FAT().GetNextClusterL(DosEntryPos1.iCluster)) |
|
2222 break; |
|
2223 |
|
2224 |
|
2225 } //for(TUint32 entryCnt=0; entryCnt< maxDirEntries; ++entryCnt) |
|
2226 |
|
2227 //--------------------------------- |
|
2228 Exit: |
|
2229 |
|
2230 if(bCacheMatchFound) |
|
2231 { |
|
2232 //-- if the position of the found in cache object is less than given, pretend that we haven't found anything |
|
2233 //-- Return to the old search, because it can be the case of the end of directory, which is quite difficult to |
|
2234 //-- detect in this situation. Note that the old part of DoFindL() leaves when the search reaches the end of dir. |
|
2235 TBool bFallBack=EFalse; |
|
2236 |
|
2237 if(DosEntryPos1.iCluster == aDosEntryPos.iCluster) |
|
2238 { |
|
2239 if(DosEntryPos1.iPos < aDosEntryPos.iPos) |
|
2240 bFallBack = ETrue; |
|
2241 } |
|
2242 else |
|
2243 { |
|
2244 if(MakeLinAddrL(DosEntryPos1) < MakeLinAddrL(aDosEntryPos)) |
|
2245 bFallBack = ETrue; |
|
2246 } |
|
2247 |
|
2248 if(bFallBack) |
|
2249 { |
|
2250 return EFalse; |
|
2251 } |
|
2252 |
|
2253 //-- Update parameters with new values |
|
2254 aStartEntryPos= StartEntryPos1; |
|
2255 aDosEntryPos = DosEntryPos1; |
|
2256 aStartEntry = StartEntry1; |
|
2257 aDosEntry = DosEntry1; |
|
2258 |
|
2259 const TInt64 mruPos = MakeLinAddrL(aDosEntryPos); |
|
2260 |
|
2261 pDirCache->MakePageMRU(mruPos); |
|
2262 |
|
2263 // only update the leaf dir cache when the original cache index is provided |
|
2264 if (aLeafDir.iClusterNum) |
|
2265 { |
|
2266 iLeafDirCache->UpdateMRUPos(TLeafDirData(aLeafDir.iClusterNum, aStartEntryPos)); |
|
2267 } |
|
2268 } |
|
2269 return bCacheMatchFound; |
|
2270 } |
|
2271 |
|
2272 //----------------------------------------------------------------------------------------- |
|
2273 |
|
2274 /** |
|
2275 initialise find helper with the target file name. |
|
2276 This is a quite expensive operation and initialisation is done only once. After this we know if the name is a legal dos one |
|
2277 and also have the corresponding generated DOS name for it. |
|
2278 |
|
2279 @param aTargetName target file name we are looking for in ::DoFindL() |
|
2280 */ |
|
2281 void CFatMountCB::TFindHelper::InitialiseL(const TDesC& aTargetName) |
|
2282 { |
|
2283 if(isInitialised) |
|
2284 return; |
|
2285 |
|
2286 TInt count = 1; |
|
2287 |
|
2288 iTargetName.Set(aTargetName); |
|
2289 isLegalDosName = IsLegalDosName(aTargetName, ETrue, EFalse, EFalse, ETrue, EFalse); |
|
2290 |
|
2291 if(isLegalDosName) |
|
2292 {//-- iShortName will contain generated short DOS name by long filename |
|
2293 iShortName = DoGenerateShortNameL(aTargetName, count, ETrue); |
|
2294 } |
|
2295 |
|
2296 isInitialised = ETrue; |
|
2297 } |
|
2298 |
|
2299 /** |
|
2300 Perform binary comparison between a given the DOS entry name and the DOS name we generated in TFindHelper::Initialise(). |
|
2301 @param apDosEntryName pointer to the DOS entry name in XXXXXXXXYYY format |
|
2302 @return ETrue if the apDosEntryName is the same as generated iShortName |
|
2303 */ |
|
2304 TBool CFatMountCB::TFindHelper::MatchDosEntryName(const TUint8* apDosEntryName) const |
|
2305 { |
|
2306 ASSERT(isInitialised); |
|
2307 |
|
2308 if(!isLegalDosName) |
|
2309 return EFalse; |
|
2310 |
|
2311 return (Mem::Compare(iShortName.Ptr(), KFatDirNameSize, apDosEntryName, KFatDirNameSize) == 0); |
|
2312 } |
|
2313 |
|
2314 //----------------------------------------------------------------------------------------- |
|
2315 const TInt KShortNameCandidatesNum = 4; |
|
2316 /** |
|
2317 Constructor of XFileCreationHelper class |
|
2318 */ |
|
2319 CFatMountCB::XFileCreationHelper::XFileCreationHelper() |
|
2320 { |
|
2321 isInitialised = EFalse; |
|
2322 } |
|
2323 |
|
2324 /** |
|
2325 Destructor of XFileCreationHelper class |
|
2326 */ |
|
2327 CFatMountCB::XFileCreationHelper::~XFileCreationHelper() |
|
2328 { |
|
2329 Close(); |
|
2330 } |
|
2331 |
|
2332 /** |
|
2333 Initialises a TFileCreationHelper object, generate a short name candidate pool. |
|
2334 |
|
2335 @param aTargetName Target file name for the potential new file. |
|
2336 @post TFileCreationHelper is fully initialised. |
|
2337 */ |
|
2338 void CFatMountCB::XFileCreationHelper::InitialiseL(const TDesC& aTargetName) |
|
2339 { |
|
2340 // close before use, to avoid memory leak |
|
2341 Close(); |
|
2342 |
|
2343 iTargetName.Set(aTargetName); |
|
2344 // generates short name candidate(s) |
|
2345 TInt count = 1; |
|
2346 while (count <= KShortNameCandidatesNum) |
|
2347 { |
|
2348 TShortName shortNameCandidate = DoGenerateShortNameL(aTargetName, count, ETrue); |
|
2349 TInt err = iShortNameCandidates.Append(shortNameCandidate); |
|
2350 User::LeaveIfError(err); |
|
2351 |
|
2352 if (count == -1) // No tilde and number is needed |
|
2353 { |
|
2354 break; |
|
2355 } |
|
2356 else |
|
2357 count++; |
|
2358 } |
|
2359 |
|
2360 // calculate number of new entries needed |
|
2361 iNumOfAddingEntries = 1; |
|
2362 isTrgNameLegalDosName = IsLegalDosName(aTargetName, EFalse, EFalse, EFalse, EFalse, ETrue); |
|
2363 if (!isTrgNameLegalDosName) |
|
2364 iNumOfAddingEntries = (TUint16) NumberOfVFatEntries(iTargetName.Length()); |
|
2365 |
|
2366 isNewEntryPosFound = EFalse; |
|
2367 isInitialised = ETrue; |
|
2368 } |
|
2369 |
|
2370 /** |
|
2371 Close function of XFileCreationHelper class |
|
2372 */ |
|
2373 void CFatMountCB::XFileCreationHelper::Close() |
|
2374 { |
|
2375 iShortNameCandidates.Close(); |
|
2376 isInitialised = EFalse; |
|
2377 } |
|
2378 |
|
2379 /** |
|
2380 Validates short name candidates. If the input dos entry name is found in the short name |
|
2381 candidate pool, the corresponding short name candidate will be removed from the pool. |
|
2382 |
|
2383 @param apDosEntryName An existing short name, to compare with the candidates. |
|
2384 @pre Object should be initialised |
|
2385 */ |
|
2386 void CFatMountCB::XFileCreationHelper::CheckShortNameCandidates(const TUint8* apDosEntryName) |
|
2387 { |
|
2388 ASSERT(isInitialised); |
|
2389 if (!isInitialised) |
|
2390 return; |
|
2391 |
|
2392 if (iShortNameCandidates.Count() > 0) |
|
2393 { |
|
2394 for (TInt i = 0; i < iShortNameCandidates.Count(); i++) |
|
2395 { |
|
2396 if (Mem::Compare(iShortNameCandidates[i].Ptr(), KFatDirNameSize, apDosEntryName, KFatDirNameSize) == 0) |
|
2397 { |
|
2398 iShortNameCandidates.Remove(i); |
|
2399 break; |
|
2400 } |
|
2401 } |
|
2402 } |
|
2403 } |
|
2404 |
|
2405 /** |
|
2406 Gets a validated short name from the short name candidate pool. |
|
2407 |
|
2408 @param aShortName On return, contains a validated short name if found, otherwise zeroed. |
|
2409 @return TInt Returns KErrNone if a validated short name found successfully, |
|
2410 else KErrNotFound is returned. |
|
2411 Returns KErrNotReady if object is not initialised. |
|
2412 @pre Object should be initialised |
|
2413 */ |
|
2414 TInt CFatMountCB::XFileCreationHelper::GetValidatedShortName(TShortName& aShortName) const |
|
2415 { |
|
2416 aShortName.Zero(); |
|
2417 |
|
2418 ASSERT(isInitialised); |
|
2419 if (!isInitialised) |
|
2420 return KErrNotReady; |
|
2421 |
|
2422 if (iShortNameCandidates.Count() > 0) |
|
2423 { |
|
2424 aShortName.Copy(iShortNameCandidates[0]); |
|
2425 return KErrNone; |
|
2426 } |
|
2427 |
|
2428 return KErrNotFound; |
|
2429 } |
|
2430 |
|
2431 //----------------------------------------------------------------------------------------- |
|
2432 |
|
2433 |
|
2434 /** |
|
2435 Scan a directory looking for aName. |
|
2436 |
|
2437 @param aTrgtName a name of an object we are looking up in directory |
|
2438 @param anAtt attributes of this object |
|
2439 @param aStartEntryPos on return in case of VFAT entry will contain start position of the VFAT dir. entry |
|
2440 @param aStartEntry on return will contain first VFAT dir entry |
|
2441 @param aDosEntryPos the search will start from this position of dir entry, on return it will contain result DOS entry position, last one for VFAT case |
|
2442 @param aDosEntry on return will contain DOS dir entry (the last one for VFAT case) |
|
2443 @param aFileName in the case of VFAT entry and on success here will be returned a long filename |
|
2444 @param anError This function might leave with this given error code |
|
2445 @param aFileCreationHelper a helper package for file creations |
|
2446 |
|
2447 @return ETrue if extracted entry is VFAT one, EFalse, if it's old DOS-style one |
|
2448 @leave can leave with anError code on error or if the search has reached the end of directory (!) |
|
2449 */ |
|
2450 TBool CFatMountCB::DoFindL(const TDesC& aTrgtName,TUint anAtt, |
|
2451 TEntryPos& aStartEntryPos,TFatDirEntry& aStartEntry, |
|
2452 TEntryPos& aDosEntryPos,TFatDirEntry& aDosEntry, |
|
2453 TDes& aFileName,TInt anError, |
|
2454 XFileCreationHelper* aFileCreationHelper, |
|
2455 const TLeafDirData& aLeafDirData) const |
|
2456 { |
|
2457 // check that the entry position to be read next is not past the end of the |
|
2458 // root directory. If this is the case then when GetDirEntryL(..) is called |
|
2459 // this will lead to MakeLinAddr(..) leaving with KErrDirFull. |
|
2460 |
|
2461 if (IsRootDir(aDosEntryPos)&&(aDosEntryPos.iPos+StartOfRootDirInBytes()>=RootDirEnd())) |
|
2462 User::Leave(anError);//Allows maximum number of entries in root directory |
|
2463 |
|
2464 __PRINT2(_L("CFatMountCB::DoFindL() drv:%d, %S"),Drive().DriveNumber(),&aTrgtName); |
|
2465 |
|
2466 TInt previousCluster=aDosEntryPos.iCluster; |
|
2467 TUint previousPosition=aDosEntryPos.iPos; |
|
2468 TInt changePreviousCluster=1; |
|
2469 TInt count=0; |
|
2470 |
|
2471 TBool trgNameIsWildCard = EFalse; //-- ETrue if the name we are looking for is a wildcard |
|
2472 TBool trgNameFullySpecified = ETrue; //-- ETrue if the name we are looking for doesn't contain wildcards |
|
2473 |
|
2474 |
|
2475 { |
|
2476 //-- find out if the name we are looking for is a wildcard ("*" or "*.*") |
|
2477 const TInt len = aTrgtName.Length(); |
|
2478 |
|
2479 if(len == 1) |
|
2480 trgNameIsWildCard = (aTrgtName[0] == '*'); |
|
2481 else if(len == 3) |
|
2482 { |
|
2483 _LIT(KAllFiles, "*.*"); |
|
2484 trgNameIsWildCard = (aTrgtName==KAllFiles); |
|
2485 } |
|
2486 |
|
2487 //-- find out if the name we are looking for contains wildcharacters: "*" or "?" |
|
2488 if(trgNameIsWildCard) |
|
2489 trgNameFullySpecified = EFalse; |
|
2490 else |
|
2491 { |
|
2492 for(TInt i=0; i<len; ++i) |
|
2493 { |
|
2494 const TChar ch = aTrgtName[i]; |
|
2495 if(ch == (TChar)'*' || ch == (TChar)'?') |
|
2496 { |
|
2497 trgNameFullySpecified = EFalse; |
|
2498 break; |
|
2499 } |
|
2500 } |
|
2501 } |
|
2502 } |
|
2503 |
|
2504 |
|
2505 TPtrC trgtNameNoDot(aTrgtName); |
|
2506 |
|
2507 TFindHelper findHelper; |
|
2508 //--------------------------------------------------- |
|
2509 //-- if we have fully specified name and directory cache is present, try to |
|
2510 //-- locate the name in the cache first to avoid reading from media |
|
2511 //-- if the entry belongs to the root directory (for FAT12,16) skip the lookup, because root directory isn't aligned by cluster size boundary, |
|
2512 //-- while directory cache pages are. For FAT32 it doesn't matter, because root dir is a usual file. |
|
2513 if(iRawDisk->DirCacheInterface() && trgNameFullySpecified && !IsRootDir(aDosEntryPos) && !aFileCreationHelper) |
|
2514 {//-- aName is fully specified, i.e doesn't contain wildcards |
|
2515 |
|
2516 findHelper.InitialiseL(trgtNameNoDot); |
|
2517 |
|
2518 const TBool bMatchFound = DoRummageDirCacheL(anAtt, aStartEntryPos, aStartEntry, aDosEntryPos, aDosEntry, aFileName, findHelper, aFileCreationHelper, aLeafDirData); |
|
2519 if(bMatchFound) |
|
2520 { |
|
2521 return(aStartEntry.IsVFatEntry()); |
|
2522 } |
|
2523 } |
|
2524 //--------------------------------------------------- |
|
2525 |
|
2526 // we need to scan ahead from the mru pos then come back to beginning, if startcluster is provided |
|
2527 TBool scanAhead = EFalse; |
|
2528 // if we have a starting cluster number (and it's not root directory in FAT16/12 case)&& |
|
2529 // we found a lastScanned entry's cluster (and it's not root directory in FAT16/12 case)&& |
|
2530 // if we don't have a starting cluster number, we draw back to original scanning algorithm |
|
2531 if (!IsRootDir(aDosEntryPos) // we don't do forward scanning for root dir & |
|
2532 && aLeafDirData.iClusterNum != 0 // if we have a starting cluster number & |
|
2533 && aLeafDirData.iMRUPos.Cluster() != 0) // if we have a starting cluster number & |
|
2534 { |
|
2535 scanAhead = ETrue; |
|
2536 aDosEntryPos = aLeafDirData.iMRUPos; |
|
2537 } |
|
2538 |
|
2539 TInt numFound = 0; |
|
2540 TEntryPos startPos = aDosEntryPos; |
|
2541 TInt clustNum = aDosEntryPos.Cluster(); |
|
2542 |
|
2543 for (TInt scanCnt = 1; scanCnt <= 2; ++scanCnt) |
|
2544 { |
|
2545 // if we are not scanning ahead, we don't need this outer for loop |
|
2546 if (!scanAhead) |
|
2547 scanCnt++; |
|
2548 |
|
2549 TBool found = EFalse; |
|
2550 |
|
2551 FOREVER //FOREVER2 -- walk through all directory entries in the current directory until find a match or directory end |
|
2552 { |
|
2553 //-- read full directory entry starting from aDosEntryPos. On return aFileName may contain assembled long filename (if the entry is VFAT) |
|
2554 //-- aDosEntry will contain a DOS entry of the directory entry we have read. |
|
2555 aStartEntryPos=aDosEntryPos; |
|
2556 User::LeaveIfError(GetDirEntry(aDosEntryPos, aDosEntry, aStartEntry, aFileName)); |
|
2557 |
|
2558 if (aDosEntry.IsEndOfDirectory()) |
|
2559 {//-- the end of directory reached. |
|
2560 |
|
2561 // if new entry position for adding has not been found yet. |
|
2562 // note aFileCreationHelper may not be initialised for pure file opening operations |
|
2563 if (aFileCreationHelper && aFileCreationHelper->IsInitialised() && !aFileCreationHelper->IsNewEntryPosFound()) |
|
2564 { |
|
2565 // if MoveToNextEntryL have gone to the next cluster which is the end of cluster chain, |
|
2566 // we pass the last scanned entry position to AddDirEntryL |
|
2567 if (IsEndOfClusterCh(aDosEntryPos.iCluster)) |
|
2568 { |
|
2569 TInt clusterSize=1<<ClusterSizeLog2(); |
|
2570 TEntryPos dummyPos(clustNum, clusterSize - KSizeOfFatDirEntry); |
|
2571 aFileCreationHelper->SetEntryAddingPos(dummyPos); |
|
2572 aFileCreationHelper->SetIsNewEntryPosFound(ETrue); |
|
2573 } |
|
2574 // or we reached the end of the directory. |
|
2575 else |
|
2576 { |
|
2577 aFileCreationHelper->SetEntryAddingPos(aDosEntryPos); |
|
2578 aFileCreationHelper->SetIsNewEntryPosFound(ETrue); |
|
2579 } |
|
2580 } |
|
2581 |
|
2582 // if we are scanning ahead and this is the first scanning, we break out to restart scanning |
|
2583 if (scanAhead && scanCnt == 1) |
|
2584 { |
|
2585 break; // from FOREVER, restart scanning |
|
2586 } |
|
2587 |
|
2588 // if (!scanAhead || scanAhead && scanCnt == 2) |
|
2589 User::Leave(anError); |
|
2590 } |
|
2591 |
|
2592 |
|
2593 // entry space searching for potential new file/directory creation |
|
2594 if (aFileCreationHelper && aFileCreationHelper->IsInitialised() && !aFileCreationHelper->IsNewEntryPosFound()) |
|
2595 { |
|
2596 if (!aDosEntry.IsErased() && !aDosEntry.IsGarbage()) |
|
2597 { |
|
2598 numFound = 0; |
|
2599 } |
|
2600 else |
|
2601 { |
|
2602 if (numFound == 0) |
|
2603 { |
|
2604 startPos = aDosEntryPos; |
|
2605 } |
|
2606 numFound++; |
|
2607 if (numFound == aFileCreationHelper->NumOfAddingEntries()) |
|
2608 { |
|
2609 aFileCreationHelper->SetEntryAddingPos(startPos); |
|
2610 aFileCreationHelper->SetIsNewEntryPosFound(ETrue); |
|
2611 } |
|
2612 } |
|
2613 } |
|
2614 |
|
2615 |
|
2616 if (IsRootDir(aDosEntryPos)&&(aDosEntryPos.iPos+StartOfRootDirInBytes()==(RootDirEnd()-KSizeOfFatDirEntry))) |
|
2617 if (aDosEntry.IsErased()) |
|
2618 { |
|
2619 User::Leave(anError);//Allows maximum number of entries in root directory |
|
2620 } |
|
2621 |
|
2622 |
|
2623 const TBool bFileNameEntry = !aDosEntry.IsCurrentDirectory() && !aDosEntry.IsParentDirectory() && !aDosEntry.IsErased() && !aDosEntry.IsGarbage(); |
|
2624 |
|
2625 if (bFileNameEntry && MatchEntryAtt(aDosEntry.Attributes(), anAtt)) |
|
2626 {//-- we have read a filename entry and entry's attributes match required; compare names then. |
|
2627 |
|
2628 if (trgNameIsWildCard) |
|
2629 { |
|
2630 found = ETrue; |
|
2631 break; //-- we were looking for '*' or '*.*', so will be satisfied with any current file name. |
|
2632 } |
|
2633 |
|
2634 |
|
2635 if (aStartEntry.IsVFatEntry()) |
|
2636 {//-- we've read a VFAT entry, aFileName is supposed to contain long filename, aDosEntry - DOS entry for this name. |
|
2637 //-- note: aFileName.Length() may be 0, while DOS entry (short name is OK) in the case of orphaned VFAT entries |
|
2638 |
|
2639 |
|
2640 // we only check short name candidates for long file names with VFAT entries, |
|
2641 // if it is a valid dos name, it will be checked by default |
|
2642 // note, for file creation cases, target name will be always fully specified |
|
2643 if (aFileCreationHelper && aFileCreationHelper->IsInitialised() && trgNameFullySpecified) |
|
2644 { |
|
2645 aFileCreationHelper->CheckShortNameCandidates(aDosEntry.Name().Ptr()); |
|
2646 } |
|
2647 |
|
2648 //-- discard trailing dots from aFileName if present |
|
2649 TPtrC ptrAssembledName = RemoveTrailingDots(aFileName); |
|
2650 |
|
2651 if(ptrAssembledName.MatchF(trgtNameNoDot) != KErrNotFound) |
|
2652 { |
|
2653 found = ETrue; |
|
2654 break; //-- OK, found a match. |
|
2655 } |
|
2656 else if (trgNameFullySpecified) |
|
2657 { |
|
2658 //-- long name assembled by GetDirEntry() doesn't match the target. But if he target name is fully specified, |
|
2659 //-- we need to compare corresponding DOS entries, because VFAT entries may be damaged, while DOS ones are OK. |
|
2660 findHelper.InitialiseL(trgtNameNoDot); |
|
2661 |
|
2662 if(findHelper.MatchDosEntryName(aDosEntry.Name().Ptr())) |
|
2663 { |
|
2664 found = ETrue; |
|
2665 break; //-- DOS entries match, success. |
|
2666 } |
|
2667 } |
|
2668 else if (!trgNameFullySpecified) |
|
2669 {//-- target name contains wildcards, we need to use MatchF with dos name |
|
2670 TBuf8<0x20> dosName8(DosNameFromStdFormat(aDosEntry.Name())); |
|
2671 TBuf<0x20> dosName; |
|
2672 LocaleUtils::ConvertToUnicodeL(dosName, dosName8); //-- convert DOS name to unicode (implies locale settings) |
|
2673 if (dosName.MatchF(trgtNameNoDot)!=KErrNotFound) |
|
2674 { |
|
2675 found = ETrue; |
|
2676 break; |
|
2677 } |
|
2678 } |
|
2679 |
|
2680 |
|
2681 } |
|
2682 else //if (aStartEntry.IsVFatEntry()) |
|
2683 {//-- we've read a legacy FAT entry, so compare DOS entries |
|
2684 findHelper.InitialiseL(trgtNameNoDot); |
|
2685 |
|
2686 if(findHelper.TrgtNameIsLegalDos()) |
|
2687 {//-- we are looking for a legal DOS name |
|
2688 if(trgNameFullySpecified) |
|
2689 {//-- if the target name is fully specified, we can yse binary comparison of the DOS entries |
|
2690 if(findHelper.MatchDosEntryName(aDosEntry.Name().Ptr())) |
|
2691 { |
|
2692 found = ETrue; |
|
2693 break; |
|
2694 } |
|
2695 } |
|
2696 else |
|
2697 {//-- target name contains wildcards, we neeed to use MatchF |
|
2698 TBuf8<0x20> dosName8(DosNameFromStdFormat(aDosEntry.Name())); |
|
2699 TBuf<0x20> dosName; |
|
2700 LocaleUtils::ConvertToUnicodeL(dosName, dosName8); //-- convert DOS name to unicode (implies locale settings) |
|
2701 if (dosName.MatchF(trgtNameNoDot)!=KErrNotFound) |
|
2702 { |
|
2703 found = ETrue; |
|
2704 break; |
|
2705 } |
|
2706 |
|
2707 } |
|
2708 } //if(findHelper.TrgtNameIsLegalDos()) |
|
2709 |
|
2710 } //else if (aStartEntry.IsVFatEntry()) |
|
2711 |
|
2712 } //if (bFileNameEntry && MatchEntryAtt(aDosEntry.Attributes(),anAtt)) |
|
2713 |
|
2714 |
|
2715 // record previous cluster number |
|
2716 clustNum = aDosEntryPos.iCluster; |
|
2717 |
|
2718 // this is the 2nd scanning and we have just passed the pos we started. |
|
2719 if (scanAhead && scanCnt == 2) |
|
2720 { |
|
2721 if (aDosEntryPos.Cluster() == aLeafDirData.iMRUPos.Cluster() |
|
2722 && aDosEntryPos.Pos() >= aLeafDirData.iMRUPos.Pos()) |
|
2723 { |
|
2724 User::Leave(anError); |
|
2725 } |
|
2726 } |
|
2727 |
|
2728 |
|
2729 MoveToNextEntryL(aDosEntryPos); //-- goto the next entry in the directory |
|
2730 |
|
2731 if (IsRootDir(aDosEntryPos)&&(aDosEntryPos.iPos+StartOfRootDirInBytes()>=RootDirEnd())) |
|
2732 { |
|
2733 User::Leave(anError);//Allows maximum number of entries in root directory |
|
2734 } |
|
2735 |
|
2736 |
|
2737 if (!scanAhead || scanCnt == 2) |
|
2738 { |
|
2739 if (aDosEntryPos.iCluster && (aDosEntryPos.iPos <= previousPosition)) |
|
2740 DoCheckFatForLoopsL(aDosEntryPos.iCluster,previousCluster,changePreviousCluster,count); |
|
2741 |
|
2742 previousPosition=aDosEntryPos.iPos; |
|
2743 } |
|
2744 } // FOREVER -- the actual scanning is done inside this loop |
|
2745 |
|
2746 |
|
2747 if (found) |
|
2748 { |
|
2749 break; |
|
2750 } |
|
2751 |
|
2752 // if not found: |
|
2753 // if we have not found in the first scanning and we are doing scanning ahead, |
|
2754 // we need to go back to the starting pos of this dir and scan from start until |
|
2755 // we reach lastscannedPos |
|
2756 if (scanAhead && scanCnt == 1) |
|
2757 { |
|
2758 aDosEntryPos = TEntryPos(aLeafDirData.iClusterNum, 0); |
|
2759 continue; |
|
2760 } |
|
2761 else |
|
2762 { |
|
2763 // there are only two exits: either found or reached end of dir in the 1st scanning |
|
2764 ASSERT(0); |
|
2765 break; |
|
2766 } |
|
2767 } // for (TInt scanCnt = 1; scanCnt <= 2; ++scanCnt) |
|
2768 |
|
2769 //--------------------------------------------------- |
|
2770 if (iRawDisk->DirCacheInterface() && aDosEntryPos.Cluster()) |
|
2771 { |
|
2772 TInt64 mruPos = MakeLinAddrL(aDosEntryPos); |
|
2773 iRawDisk->DirCacheInterface()->MakePageMRU(mruPos); |
|
2774 |
|
2775 // only update the leaf dir cache when the original cache index is provided |
|
2776 if (aLeafDirData.iClusterNum) |
|
2777 { |
|
2778 iLeafDirCache->UpdateMRUPos(TLeafDirData(aLeafDirData.iClusterNum, aDosEntryPos)); |
|
2779 } |
|
2780 } |
|
2781 |
|
2782 return (aStartEntry.IsVFatEntry()); |
|
2783 } |
|
2784 |
|
2785 //----------------------------------------------------------------------------------------- |
|
2786 /** |
|
2787 Locate an directory entry entry from its full path name. |
|
2788 |
|
2789 @param aName a name of an object we are looking for |
|
2790 @param anAtt attributes of this object |
|
2791 @param anEntry on return will contain first VFAT dir entry |
|
2792 @param anEntryPos on return in case of VFAT entry will contain start position of the VFAT dir. entry |
|
2793 |
|
2794 @leave can leave with KErrNotFound if the search has reached the end of directory |
|
2795 */ |
|
2796 void CFatMountCB::FindEntryStartL(const TDesC& aName,TUint anAtt,TFatDirEntry& anEntry,TEntryPos& anEntryPos) const |
|
2797 { |
|
2798 __PRINT(_L("CFatMountCB::FindEntryStartL()")); |
|
2799 TInt namePos=aName.LocateReverse(KPathDelimiter)+1; // There is always a path delimiter |
|
2800 TFileName fileName; |
|
2801 TLeafDirData leafDir; |
|
2802 TEntryPos dosEntryPos(FindLeafDirL(aName.Left(namePos),leafDir),0); |
|
2803 TFatDirEntry dosEntry; |
|
2804 |
|
2805 DoFindL(aName.Mid(namePos),anAtt,anEntryPos,anEntry,dosEntryPos,dosEntry,fileName,KErrNotFound,NULL,leafDir); |
|
2806 } |
|
2807 |
|
2808 |
|
2809 //----------------------------------------------------------------------------------------- |
|
2810 |
|
2811 /** |
|
2812 Locate an directory entry entry from its full path name. |
|
2813 |
|
2814 @param aName a name of an object we are looking for |
|
2815 @param anAtt attributes of this object |
|
2816 @param anEntry on return will contain first VFAT dir entry |
|
2817 @param anEntryPos on return in case of VFAT entry will contain start position of the VFAT dir. entry |
|
2818 |
|
2819 @leave can leave with KErrNotFound if the search has reached the end of directory |
|
2820 */ |
|
2821 void CFatMountCB::FindEntryStartL(const TDesC& aName,TUint anAtt,TFatDirEntry& anEntry,TEntryPos& anEntryPos,XFileCreationHelper* aFileCreationHelper) const |
|
2822 { |
|
2823 __PRINT(_L("CFatMountCB::FindEntryStartL()")); |
|
2824 TInt namePos=aName.LocateReverse(KPathDelimiter)+1; // There is always a path delimiter |
|
2825 TFileName fileName; |
|
2826 TLeafDirData leafDir; |
|
2827 TEntryPos dosEntryPos(FindLeafDirL(aName.Left(namePos),leafDir),0); |
|
2828 TFatDirEntry dosEntry; |
|
2829 DoFindL(aName.Mid(namePos),anAtt,anEntryPos,anEntry,dosEntryPos,dosEntry,fileName,KErrNotFound,aFileCreationHelper,leafDir); |
|
2830 } |
|
2831 |
|
2832 //----------------------------------------------------------------------------------------- |
|
2833 void CFatMountCB::FindDosNameL(const TDesC& aName,TUint anAtt,TEntryPos& aDosEntryPos,TFatDirEntry& aDosEntry,TDes& aFileName,TInt anError) const |
|
2834 // |
|
2835 // Scan a directory looking for aName. |
|
2836 // aCluster and anEntryAddr give the location of the entry. |
|
2837 // |
|
2838 { |
|
2839 |
|
2840 __PRINT(_L("CFatMountCB::FindDosNameL()")); |
|
2841 TEntryPos startPos; |
|
2842 TFatDirEntry startEntry; |
|
2843 |
|
2844 TLeafDirData leafDir; // leaf dir data is zero initialized, no scannig ahead |
|
2845 DoFindL(aName,anAtt,startPos,startEntry,aDosEntryPos,aDosEntry,aFileName,anError,NULL,leafDir); |
|
2846 } |
|
2847 //----------------------------------------------------------------------------------------- |
|
2848 |
|
2849 void CFatMountCB::AddDirEntryL(TEntryPos& aPos,TInt aNumOfEntries) |
|
2850 // |
|
2851 // Find space for a new directory entry. Leave KErrEof if no space |
|
2852 // |
|
2853 { |
|
2854 |
|
2855 __PRINT(_L("CFatMountCB::AddDirEntryL")); |
|
2856 TInt numFound=0; |
|
2857 TFatDirEntry entry; |
|
2858 TEntryPos startPos(RootIndicator(),0); |
|
2859 TInt clusterNum=aPos.iCluster; |
|
2860 FOREVER |
|
2861 { |
|
2862 ReadDirEntryL(aPos,entry); |
|
2863 if (entry.IsEndOfDirectory()) |
|
2864 break; |
|
2865 if (!entry.IsErased() && !entry.IsGarbage()) |
|
2866 numFound=0; |
|
2867 else |
|
2868 { |
|
2869 if (numFound==0) |
|
2870 startPos=aPos; |
|
2871 numFound++; |
|
2872 if (numFound==aNumOfEntries) |
|
2873 { |
|
2874 aPos=startPos; |
|
2875 return; |
|
2876 } |
|
2877 } |
|
2878 clusterNum=aPos.iCluster; |
|
2879 MoveToNextEntryL(aPos); |
|
2880 if (IsRootDir(aPos)&&(StartOfRootDirInBytes()+aPos.iPos==RootDirEnd())) |
|
2881 // No end of directory marker at end of root directory |
|
2882 User::Leave(KErrDirFull); |
|
2883 } |
|
2884 |
|
2885 TUint clusterSize=1<<ClusterSizeLog2(); |
|
2886 if (IsEndOfClusterCh(aPos.iCluster)) |
|
2887 { // End of last cluster in directory |
|
2888 aPos.iCluster=clusterNum; |
|
2889 aPos.iPos=clusterSize; |
|
2890 } |
|
2891 |
|
2892 TEntryPos eofPos(aPos.iCluster,aPos.iPos+KSizeOfFatDirEntry*aNumOfEntries); |
|
2893 |
|
2894 if (IsRootDir(aPos)) |
|
2895 { // Special case of root directory |
|
2896 if (eofPos.iPos+StartOfRootDirInBytes()>RootDirEnd()) |
|
2897 User::Leave(KErrDirFull); |
|
2898 else |
|
2899 return; |
|
2900 } |
|
2901 |
|
2902 if (eofPos.iPos==clusterSize) |
|
2903 return; // No need to allocate |
|
2904 if (eofPos.iPos>clusterSize) |
|
2905 { |
|
2906 TInt numNeeded=eofPos.iPos>>ClusterSizeLog2(); |
|
2907 if(IsRuggedFSys()) |
|
2908 { |
|
2909 ExtendClusterListZeroedL(numNeeded,eofPos.iCluster); |
|
2910 } |
|
2911 else |
|
2912 { |
|
2913 FAT().ExtendClusterListL(numNeeded,eofPos.iCluster); |
|
2914 ZeroDirClusterL(eofPos.iCluster); |
|
2915 } |
|
2916 |
|
2917 eofPos.iPos-=numNeeded<<ClusterSizeLog2(); |
|
2918 if(aPos.iPos==clusterSize) |
|
2919 { |
|
2920 if (!FAT().GetNextClusterL(aPos.iCluster)) |
|
2921 { |
|
2922 __PRINT(_L("CFatMountCB::AddDirEntryL corrupt#1")) |
|
2923 User::Leave(KErrCorrupt); |
|
2924 } |
|
2925 aPos.iPos=0; |
|
2926 } |
|
2927 } |
|
2928 else if(Drive().IsRemovable()) |
|
2929 { |
|
2930 // check if entry is already zeroed |
|
2931 ReadDirEntryL(eofPos,entry); |
|
2932 if(!entry.IsEndOfDirectory()) |
|
2933 { |
|
2934 // some removable media may not have directory zeroed |
|
2935 entry.SetEndOfDirectory(); |
|
2936 WriteDirEntryL(eofPos,entry); |
|
2937 } |
|
2938 } |
|
2939 } |
|
2940 |
|
2941 /** |
|
2942 Zero fill a cluster |
|
2943 @param aCluster cluster number to zero-fill |
|
2944 */ |
|
2945 void CFatMountCB::ZeroDirClusterL(TInt aCluster) |
|
2946 { |
|
2947 |
|
2948 __PRINT1(_L("CFatMountCB::ZeroDirClusterL %d"),aCluster); |
|
2949 |
|
2950 const TUint32 KClusterSz= 1<<ClusterSizeLog2(); |
|
2951 const TUint32 KMaxBufSz = KClusterSz; //-- max. nuffer size is a cluster |
|
2952 const TUint32 KMinBufSz = 1<<SectorSizeLog2(); //-- min. buffer size is 1 sector (for OOM case) |
|
2953 |
|
2954 //-- allocate a buffer for zero-filling a cluster |
|
2955 RBuf8 buf; |
|
2956 CleanupClosePushL(buf); |
|
2957 |
|
2958 if(buf.CreateMax(KMaxBufSz) != KErrNone) |
|
2959 buf.CreateMaxL(KMinBufSz); //-- OOM, try to create smaller buffer |
|
2960 |
|
2961 buf.FillZ(); |
|
2962 |
|
2963 TEntryPos entryPos(aCluster,0); |
|
2964 |
|
2965 //-- write buffer to the beginning of the directory file. |
|
2966 DirWriteL(entryPos, buf); //-- use special interface to access FAT directory file |
|
2967 |
|
2968 //-- fill in the rest of the cluster if we used a small buffer |
|
2969 if((TUint32)buf.Size() < KClusterSz) //-- KMaxBufSz may == KMinBufSz if we have 1 sector per cluster |
|
2970 { |
|
2971 const TInt restCnt = SectorsPerCluster() - 1; |
|
2972 ASSERT(restCnt >=1); |
|
2973 |
|
2974 for(TInt i=0; i<restCnt; ++i) |
|
2975 { |
|
2976 entryPos.iPos += KMinBufSz; |
|
2977 DirWriteL(entryPos, buf); //-- use special interface to access FAT directory file |
|
2978 } |
|
2979 |
|
2980 } |
|
2981 |
|
2982 CleanupStack::PopAndDestroy(&buf); |
|
2983 } |
|
2984 |
|
2985 |
|
2986 /** |
|
2987 Internal method. Retrieves directory entry from given position. |
|
2988 |
|
2989 @param aPos on enter shall contain start position, from where the entry will be read. On return contains position of the DOS entry (the last one for object name for the VFAT case) |
|
2990 @param aDosEntry On return contains DOS entry for the VFAT case |
|
2991 @param aStartEntry On return contains start entry of the directory object for the VFAT case |
|
2992 @param aLongFileName On return contains VFAT or long filename |
|
2993 |
|
2994 @return ETrue if whole FAT entry is OK: only 1 entry for DOS name or _ALL_ entries for a long name |
|
2995 EFalse if there was an error in assembling entries to the long file name. In this case this entry shall be ignored by upper level. |
|
2996 |
|
2997 can leave because of ReadDirEntryL() and MoveToNextEntryL() [end of dir]. |
|
2998 */ |
|
2999 TBool CFatMountCB::DoGetDirEntryL(TEntryPos& aPos, TFatDirEntry& aDosEntry, TFatDirEntry& aStartEntry, TDes& aLongFileName) const |
|
3000 { |
|
3001 |
|
3002 // __PRINT3(_L("CFatMountCB::GetDirEntryL() drv:%d, pos:%d:%d"), Drive().DriveNumber(), aPos.iCluster, aPos.iPos); |
|
3003 |
|
3004 ReadDirEntryL(aPos,aStartEntry); |
|
3005 aDosEntry=aStartEntry; |
|
3006 if (!aDosEntry.IsVFatEntry() || aDosEntry.IsErased() || aDosEntry.IsGarbage()) |
|
3007 {//-- This is either a 8.3 FAT entry or garbage |
|
3008 aLongFileName.SetLength(0); |
|
3009 return ETrue; |
|
3010 } |
|
3011 |
|
3012 //-- process VFAT entries |
|
3013 |
|
3014 if(!aDosEntry.IsLongNameStart()) |
|
3015 return EFalse; //-- wrong counter in the 1st VFat entry, consider it as orphaned |
|
3016 |
|
3017 |
|
3018 TInt count = aDosEntry.NumFollowing(); //-- count of the following VFat entries |
|
3019 |
|
3020 TBuf16<KMaxVFatEntryName> vBuf(KMaxVFatEntryName); |
|
3021 aDosEntry.ReadVFatEntry(vBuf); |
|
3022 |
|
3023 TInt vLength=vBuf.Locate('\0'); |
|
3024 if (vLength==KErrNotFound) |
|
3025 vLength=KMaxVFatEntryName; |
|
3026 |
|
3027 vBuf.SetLength(vLength); |
|
3028 |
|
3029 const TInt nameLen = vLength+KMaxVFatEntryName*(count-1); |
|
3030 if(nameLen <= 0 || nameLen > KMaxFileName) |
|
3031 return EFalse; //-- wrong long file name length, consider VFAT entry as orphaned |
|
3032 |
|
3033 aLongFileName.SetLength(nameLen); |
|
3034 |
|
3035 const TUint8 entryCheckSum = aDosEntry.CheckSum(); //-- check sum from the 1st VFat entry |
|
3036 |
|
3037 while (count--) |
|
3038 { |
|
3039 TPtr fileNamePtr(&aLongFileName[0]+KMaxVFatEntryName*count,aLongFileName.Length()-KMaxVFatEntryName*count); |
|
3040 fileNamePtr.Copy(vBuf); |
|
3041 if (count==0) |
|
3042 break; //-- all VFat entries read, only DOS entry remained |
|
3043 |
|
3044 MoveToNextEntryL(aPos); |
|
3045 ReadDirEntryL(aPos,aDosEntry); |
|
3046 |
|
3047 //-- check if it is correct VFat entry. |
|
3048 //-- if not, this is the "orphaned" entry and will be ignored |
|
3049 if(!aDosEntry.IsVFatEntry() || aDosEntry.IsErased() || entryCheckSum != aDosEntry.CheckSum() || aDosEntry.NumFollowing() != count) |
|
3050 return EFalse; //-- bad VFAT entry |
|
3051 |
|
3052 aDosEntry.ReadVFatEntry(vBuf); |
|
3053 } |
|
3054 |
|
3055 if (IsRootDir(aPos)&&(aPos.iPos+StartOfRootDirInBytes()==(RootDirEnd()-KSizeOfFatDirEntry))) |
|
3056 return ETrue;//Allows maximum number of entries in root directory |
|
3057 |
|
3058 //-- read the last, DOS FAT entry |
|
3059 MoveToNextEntryL(aPos); |
|
3060 ReadDirEntryL(aPos,aDosEntry); |
|
3061 |
|
3062 //-- check if it is corect |
|
3063 if(aDosEntry.IsEndOfDirectory() || aDosEntry.IsErased() || aDosEntry.IsVFatEntry()) |
|
3064 return EFalse; //-- Bad DOS entry |
|
3065 |
|
3066 //-- verify ChechSum here if it is incorrect, use DOS name only |
|
3067 const TUint8 calcNameChkSum = CalculateShortNameCheckSum(aDosEntry.Name()); |
|
3068 if(calcNameChkSum != entryCheckSum) |
|
3069 { |
|
3070 aLongFileName.SetLength(0);//-- don't use long filename |
|
3071 __PRINT2(_L("CFatMountCB::GetDirEntryL() CheckSum mismatch: VFat:0x%x, DOS:0x%d"),entryCheckSum, calcNameChkSum); |
|
3072 } |
|
3073 |
|
3074 return ETrue; |
|
3075 } |
|
3076 |
|
3077 |
|
3078 /** |
|
3079 Read a number of VFAT entries from the directory file. |
|
3080 for parameters see DoGetDirEntryL() |
|
3081 |
|
3082 @return KErrNone if everything is OK, system wide error code otherwise |
|
3083 |
|
3084 */ |
|
3085 TInt CFatMountCB::GetDirEntry(TEntryPos& aPos,TFatDirEntry& aDosEntry,TFatDirEntry& aStartEntry,TDes& aLongFileName) const |
|
3086 { |
|
3087 |
|
3088 TBool bEntryOK=ETrue; |
|
3089 TRAPD(nErr, bEntryOK = DoGetDirEntryL(aPos, aDosEntry, aStartEntry, aLongFileName)); |
|
3090 |
|
3091 if(nErr !=KErrNone) |
|
3092 return nErr; |
|
3093 |
|
3094 if(!bEntryOK) |
|
3095 {//-- DoGetDirEntryL could not assemble whole VFat entry, probably some parts of it are damaged. |
|
3096 //-- consider it as an "orphaned" entry and skip |
|
3097 aDosEntry.iData[0] = 0xFF; // Mark entry as garbage |
|
3098 aLongFileName.SetLength(0); // No long filename |
|
3099 } |
|
3100 |
|
3101 return KErrNone; |
|
3102 } |
|
3103 |
|
3104 void CFatMountCB::MoveToNextEntryL(TEntryPos& aPos) const |
|
3105 // |
|
3106 // If anEntry is at the end of the cluster, and we are not the root dir, |
|
3107 // move it to the next in the list. |
|
3108 // |
|
3109 { |
|
3110 |
|
3111 // __PRINT(_L("CFatMountCB::MoveToNextEntryL")); |
|
3112 if (IsEndOfClusterCh(aPos.iCluster)) |
|
3113 return; |
|
3114 const TUint temp = 1<<ClusterSizeLog2(); |
|
3115 if (aPos.iPos+KSizeOfFatDirEntry!=temp || IsRootDir(aPos)) |
|
3116 { |
|
3117 aPos.iPos+=KSizeOfFatDirEntry; |
|
3118 } |
|
3119 else |
|
3120 { |
|
3121 if (FAT().GetNextClusterL(aPos.iCluster)==EFalse) |
|
3122 { |
|
3123 SetEndOfClusterCh(aPos.iCluster); |
|
3124 } |
|
3125 aPos.iPos=0; |
|
3126 } |
|
3127 } |
|
3128 |
|
3129 //----------------------------------------------------------------------------------------- |
|
3130 |
|
3131 /** |
|
3132 Starting from a VFat entry walk down the directory until the associated dos entry is found |
|
3133 |
|
3134 @param aPos in: VFAT entry position. out: if this is a VFAT entry set, it will be DOS entry position. otherwise not changed |
|
3135 @param anEntry on return will contain DOS dir. entry contents (if aPos points to the VFAT entry) |
|
3136 */ |
|
3137 void CFatMountCB::MoveToDosEntryL(TEntryPos& aPos,TFatDirEntry& anEntry) const |
|
3138 { |
|
3139 |
|
3140 //__PRINT(_L("CFatMountCB::MoveToDosEntryL")); |
|
3141 if (anEntry.IsVFatEntry()==EFalse) |
|
3142 return; |
|
3143 FOREVER |
|
3144 { |
|
3145 MoveToNextEntryL(aPos); |
|
3146 ReadDirEntryL(aPos,anEntry); |
|
3147 if (anEntry.IsVFatEntry()==EFalse) |
|
3148 break; |
|
3149 if (IsRootDir(aPos)&&(aPos.iPos+StartOfRootDirInBytes()==(RootDirEnd()-KSizeOfFatDirEntry))) |
|
3150 break; // Allows maximum number of entries in root directory |
|
3151 } |
|
3152 } |
|
3153 |
|
3154 //----------------------------------------------------------------------------------------- |
|
3155 |
|
3156 /** Read the Uid of the entry starting at aCluster */ |
|
3157 void CFatMountCB::ReadUidL(TInt aCluster,TEntry& anEntry) const |
|
3158 { |
|
3159 |
|
3160 __PRINT1(_L("CFatMountCB::ReadUidL(%d)"), aCluster); |
|
3161 |
|
3162 if((TUint)aCluster < KFatFirstSearchCluster || (TUint)aCluster >= UsableClusters()+KFatFirstSearchCluster) |
|
3163 User::Leave(KErrCorrupt); |
|
3164 |
|
3165 TBuf8<sizeof(TCheckedUid)> uidBuf; |
|
3166 iRawDisk->ReadCachedL(FAT().DataPositionInBytes(aCluster),sizeof(TCheckedUid),uidBuf); |
|
3167 __ASSERT_DEBUG(uidBuf.Length()==sizeof(TCheckedUid),Fault(EFatReadUidFailed)); |
|
3168 TCheckedUid uid(uidBuf); |
|
3169 anEntry.iType=uid.UidType(); |
|
3170 } |
|
3171 |
|
3172 //----------------------------------------------------------------------------------------- |
|
3173 |
|
3174 /** |
|
3175 Read file section without opening this file on a file server side. |
|
3176 |
|
3177 @param aName file name; all trailing dots from the name will be removed |
|
3178 @param aFilePos start read position within a file |
|
3179 @param aLength how many bytes to read; on return will be how many bytes actually read |
|
3180 @param aDes local buffer desctriptor |
|
3181 @param aMessage from file server, used to write data to the buffer in different address space. |
|
3182 |
|
3183 @leave on media read error |
|
3184 */ |
|
3185 void CFatMountCB::ReadSectionL(const TDesC& aName,TInt aPos,TAny* aTrg,TInt aLength,const RMessagePtr2& aMessage) |
|
3186 { |
|
3187 __PRINT4(_L("CFatMountCB::ReadSectionL, drv:%d, pos:%d, len:%d, FN:%S"), DriveNumber(), aPos, aLength, &aName); |
|
3188 |
|
3189 CheckStateConsistentL(); |
|
3190 |
|
3191 TEntryPos dosEntryPos(RootIndicator(),0); |
|
3192 TFatDirEntry dosEntry; |
|
3193 TFileName fileName; |
|
3194 |
|
3195 |
|
3196 TInt namePos=RemoveTrailingDots(aName).LocateReverse(KPathDelimiter)+1; // There is always a path delimiter |
|
3197 TLeafDirData leafDir; |
|
3198 dosEntryPos.iCluster=FindLeafDirL(RemoveTrailingDots(aName).Left(namePos), leafDir); |
|
3199 dosEntryPos.iPos=0; |
|
3200 TEntryPos startPos; |
|
3201 TFatDirEntry startEntry; |
|
3202 DoFindL(RemoveTrailingDots(aName).Mid(namePos),KEntryAttMaskSupported, |
|
3203 startPos,startEntry,dosEntryPos,dosEntry, |
|
3204 fileName,KErrNotFound, |
|
3205 NULL, |
|
3206 leafDir); |
|
3207 |
|
3208 // Check that reading from aPos for aLength lies within the file |
|
3209 // if aPos is within the file, and aLength is too long, read up to EOF |
|
3210 // If aPos is beyond the end of the file, return a zero length descriptor |
|
3211 |
|
3212 TUint32 fileSize = dosEntry.Size(); |
|
3213 if ((TUint)aPos>=fileSize) |
|
3214 User::Leave(KErrEof); |
|
3215 |
|
3216 if ((TUint)(aPos+aLength)>fileSize) |
|
3217 aLength=fileSize-aPos; |
|
3218 |
|
3219 TInt cluster=StartCluster(dosEntry); |
|
3220 TInt pos = aPos; |
|
3221 |
|
3222 TInt endCluster; |
|
3223 TInt clusterSize=1<<ClusterSizeLog2(); // Size of file clusters |
|
3224 TInt readTotal = 0; |
|
3225 |
|
3226 // Total number of clusters in file |
|
3227 TInt maxClusters=((fileSize+clusterSize-1)>>ClusterSizeLog2()); |
|
3228 |
|
3229 // Read data |
|
3230 FOREVER |
|
3231 { |
|
3232 // Get the maximum number of clusters that can be read contiguously |
|
3233 TInt clusterListLen=FAT().CountContiguousClustersL(cluster,endCluster,maxClusters); |
|
3234 __ASSERT_DEBUG(clusterListLen>0,Fault(EReadFileSectionFailed)); |
|
3235 |
|
3236 // If start position within this block, then read some data |
|
3237 if (pos<(clusterListLen<<ClusterSizeLog2())) |
|
3238 { |
|
3239 // Read the remaining length or the entire cluster block whichever is smaller |
|
3240 TInt readLength = Min(aLength-readTotal,(clusterListLen<<ClusterSizeLog2())-pos); |
|
3241 __ASSERT_DEBUG(readLength>0,Fault(EReadFileSectionFailed)); |
|
3242 TInt64 dataAddress=(FAT().DataPositionInBytes(cluster))+pos; |
|
3243 iRawDisk->ReadL(dataAddress,readLength,aTrg,aMessage,readTotal); |
|
3244 readTotal += readLength; |
|
3245 |
|
3246 if (readTotal == aLength) |
|
3247 return; |
|
3248 |
|
3249 pos += readLength; |
|
3250 } |
|
3251 |
|
3252 // Get the next cluster in file |
|
3253 pos-=(clusterListLen<<ClusterSizeLog2()); |
|
3254 #if defined(_DEBUG) |
|
3255 TBool remainingClusters= |
|
3256 #endif |
|
3257 ((CFatMountCB*)this)->FAT().GetNextClusterL(endCluster); |
|
3258 __ASSERT_DEBUG(remainingClusters,Fault(EReadFileSectionFailed)); |
|
3259 cluster=endCluster; |
|
3260 } |
|
3261 } |
|
3262 |
|
3263 |
|
3264 //----------------------------------------------------------------------------------------- |
|
3265 |
|
3266 void CFatMountCB::RawReadL(TInt64 aPos,TInt aLength,const TAny* aTrg,TInt anOffset,const RMessagePtr2& aMessage) const |
|
3267 // |
|
3268 // Read aLength of data from disk directly to thread relative descriptor |
|
3269 // |
|
3270 { |
|
3271 iRawDisk->ReadL(aPos,aLength,aTrg,aMessage,anOffset); |
|
3272 } |
|
3273 |
|
3274 //----------------------------------------------------------------------------------------- |
|
3275 |
|
3276 void CFatMountCB::RawWriteL(TInt64 aPos,TInt aLength,const TAny* aSrc,TInt anOffset,const RMessagePtr2& aMessage) |
|
3277 // |
|
3278 // Write aLength of data from thread relative descriptor to disk |
|
3279 // |
|
3280 { |
|
3281 CheckWritableL(); |
|
3282 |
|
3283 //-- check if we are trying to write to the FAT directly and wait until FAT scan thread finishes in this case. |
|
3284 FAT().RequestRawWriteAccess(aPos, aLength); |
|
3285 |
|
3286 iRawDisk->WriteL(aPos,aLength,aSrc,aMessage,anOffset); |
|
3287 //-- Note: FAT directory cache will be invalidated in MountL() |
|
3288 } |
|
3289 |
|
3290 //----------------------------------------------------------------------------------------- |
|
3291 /** |
|
3292 This method must be used when writing to the FAT directory file. |
|
3293 If FAT directory cache is present on this drive, it will be used. |
|
3294 @param aPos entry media position |
|
3295 @param aDes data descriptor |
|
3296 */ |
|
3297 void CFatMountCB::DirWriteL(const TEntryPos& aPos,const TDesC8& aDes) |
|
3298 { |
|
3299 CheckWritableL(); |
|
3300 const TInt64 posAddr=MakeLinAddrL(aPos); |
|
3301 |
|
3302 if(!iRawDisk->DirCacheInterface()) |
|
3303 { |
|
3304 iRawDisk->WriteCachedL(posAddr,aDes); |
|
3305 } |
|
3306 else |
|
3307 {//-- if there is an interface to the FAT directory cache, use it |
|
3308 iRawDisk->DirCacheInterface()->WriteL(posAddr, aDes); |
|
3309 } |
|
3310 } |
|
3311 |
|
3312 //----------------------------------------------------------------------------------------- |
|
3313 |
|
3314 /** |
|
3315 This method must be used when reading from the FAT directory file. |
|
3316 If FAT directory cache is present on this drive, it will be used. |
|
3317 |
|
3318 @param aPos entry media position |
|
3319 @param aLength how many bytes to read |
|
3320 @param aDes input data descriptor |
|
3321 */ |
|
3322 void CFatMountCB::DirReadL(const TEntryPos& aPos, TInt aLength, TDes8& aDes) const |
|
3323 { |
|
3324 const TInt64 posAddr=MakeLinAddrL(aPos); |
|
3325 |
|
3326 if(!iRawDisk->DirCacheInterface()) |
|
3327 { |
|
3328 iRawDisk->ReadCachedL(posAddr,aLength,aDes); |
|
3329 } |
|
3330 else |
|
3331 {//-- if there is an interface to the FAT directory cache, use it |
|
3332 iRawDisk->DirCacheInterface()->ReadL(posAddr, aLength, aDes); |
|
3333 } |
|
3334 } |
|
3335 |
|
3336 //----------------------------------------------------------------------------------------- |
|
3337 |
|
3338 void CFatMountCB::WriteDirEntryL(const TEntryPos& aPos,const TFatDirEntry& aDirEntry) |
|
3339 // |
|
3340 // Write a FAT directory entry to disk. |
|
3341 // Assumes sufficient space has been created for it by AddDirEntry. |
|
3342 // |
|
3343 { |
|
3344 |
|
3345 __PRINT(_L("CFatMountCB::WriteDirEntryL")); |
|
3346 |
|
3347 //-- use special interface to access FAT directory file |
|
3348 DirWriteL(aPos,TPtrC8((TUint8*)&aDirEntry,KSizeOfFatDirEntry)); |
|
3349 } |
|
3350 |
|
3351 //----------------------------------------------------------------------------------------- |
|
3352 |
|
3353 void CFatMountCB::EraseDirEntryL(const TEntryPos& aPos) |
|
3354 // |
|
3355 // Mark a dir entry as erased |
|
3356 // |
|
3357 { |
|
3358 |
|
3359 __PRINT(_L("CFatMountCB::EraseDirEntryL")); |
|
3360 if(!iLeafDirCache && iLastLeafDir) |
|
3361 iLastLeafDir->Des().SetLength(0); |
|
3362 |
|
3363 //-- use special interface to access FAT directory file |
|
3364 DirWriteL(aPos,TPtrC8((TUint8*)&KEntryErasedMarker,sizeof(TUint8))); |
|
3365 } |
|
3366 |
|
3367 //----------------------------------------------------------------------------------------- |
|
3368 |
|
3369 void CFatMountCB::ReadDirEntryL(const TEntryPos& aPos,TFatDirEntry& aDirEntry) const |
|
3370 // |
|
3371 // Read a FAT directory entry to disk |
|
3372 // |
|
3373 { |
|
3374 |
|
3375 // __PRINT(_L("CFatMountCB::ReadDirEntryL")); |
|
3376 if (IsEndOfClusterCh(aPos.iCluster)) |
|
3377 { |
|
3378 aDirEntry.InitZ(); |
|
3379 return; |
|
3380 } |
|
3381 TPtr8 buf=TPtr8((TUint8*)&aDirEntry,KSizeOfFatDirEntry); |
|
3382 |
|
3383 //-- use special interface to access FAT directory file |
|
3384 DirReadL(aPos,KSizeOfFatDirEntry,buf); |
|
3385 } |
|
3386 |
|
3387 //----------------------------------------------------------------------------------------- |
|
3388 |
|
3389 /** |
|
3390 Enlarge the disk's size. |
|
3391 This method can be called only for variable size media, i.e. RAM drive |
|
3392 |
|
3393 @param aSize size increment (bytes) |
|
3394 */ |
|
3395 void CFatMountCB::EnlargeL(TInt aSize) |
|
3396 { |
|
3397 __PRINT2(_L("CFatMountCB::EnlargeL by 0x%x currentsize=0x%x"),aSize,iSize); |
|
3398 |
|
3399 ASSERT(iRamDrive); |
|
3400 |
|
3401 TInt maxSize; |
|
3402 if (HAL::Get(HAL::EMaxRAMDriveSize, maxSize) == KErrNone && iSize + aSize > maxSize) |
|
3403 User::Leave(KErrDiskFull); |
|
3404 User::LeaveIfError(LocalDrive()->Enlarge(aSize)); |
|
3405 iSize+=aSize; |
|
3406 |
|
3407 if (&FAT()) |
|
3408 { |
|
3409 FAT().InitializeL(); |
|
3410 } |
|
3411 |
|
3412 if (&RawDisk()) |
|
3413 { |
|
3414 RawDisk().InitializeL(); |
|
3415 } |
|
3416 |
|
3417 } |
|
3418 |
|
3419 //----------------------------------------------------------------------------------------- |
|
3420 |
|
3421 void CFatMountCB::ReduceSizeL(TInt aPos,TInt aLength) |
|
3422 // |
|
3423 // Reduce the disk's size |
|
3424 // |
|
3425 { |
|
3426 |
|
3427 __PRINT2(_L("CFatMountCB::ReduceSizeL aPos=0x%x aLength=0x%x"),aPos,aLength); |
|
3428 User::LeaveIfError(LocalDrive()->ReduceSize(aPos,aLength)); |
|
3429 iSize-=aLength; |
|
3430 } |
|
3431 |
|
3432 //----------------------------------------------------------------------------------------- |
|
3433 |
|
3434 TInt64 CFatMountCB::MakeLinAddrL(const TEntryPos& aPos) const |
|
3435 // |
|
3436 // Convert cluster/position into linear address |
|
3437 // |
|
3438 { |
|
3439 |
|
3440 //__PRINT2(_L("CFatMountCB::MakeLinAddrL, cl:%d, pos:%d"), aPos.iCluster, aPos.iPos); |
|
3441 if (!IsRootDir(aPos)) |
|
3442 { |
|
3443 TInt relPos=ClusterRelativePos(aPos.iPos); |
|
3444 return FAT().DataPositionInBytes(aPos.iCluster)+relPos; |
|
3445 } |
|
3446 if (aPos.iPos+StartOfRootDirInBytes()>=RootDirEnd()) |
|
3447 User::Leave(KErrDirFull); // Past last root dir entry |
|
3448 return StartOfRootDirInBytes()+aPos.iPos; |
|
3449 } |
|
3450 |
|
3451 //----------------------------------------------------------------------------------------- |
|
3452 |
|
3453 void CFatMountCB::GetShortNameL(const TDesC& aLongName,TDes& aShortName) |
|
3454 // |
|
3455 // Get the short name associated with a long file name |
|
3456 // |
|
3457 { |
|
3458 __PRINT(_L("CFatMountCB::GetShortNameL")); |
|
3459 TEntryPos firstEntryPos(RootIndicator(),0); |
|
3460 TFatDirEntry firstEntry; |
|
3461 FindEntryStartL(aLongName,KEntryAttMaskSupported,firstEntry,firstEntryPos); |
|
3462 MoveToDosEntryL(firstEntryPos,firstEntry); |
|
3463 TBuf8<0x20> dosName(DosNameFromStdFormat(firstEntry.Name())); |
|
3464 LocaleUtils::ConvertToUnicodeL(aShortName, dosName); |
|
3465 } |
|
3466 |
|
3467 //----------------------------------------------------------------------------------------- |
|
3468 |
|
3469 void CFatMountCB::GetLongNameL(const TDesC& aShortName,TDes& aLongName) |
|
3470 // |
|
3471 // Get the long name associated with a short file name |
|
3472 // |
|
3473 { |
|
3474 __PRINT(_L("CFatMountCB::GetLongNameL")); |
|
3475 TEntryPos pos(RootIndicator(),0); |
|
3476 TFatDirEntry entry; |
|
3477 const TInt namePos=aShortName.LocateReverse(KPathDelimiter)+1; // There is always a path delimiter |
|
3478 const TPtrC shortNameWithoutPathDelimiter(aShortName.Mid(namePos)); |
|
3479 __ASSERT_ALWAYS(shortNameWithoutPathDelimiter.Length()<=12,User::Leave(KErrBadName)); |
|
3480 |
|
3481 TLeafDirData leafDir; |
|
3482 pos.iCluster=FindLeafDirL(aShortName.Left(namePos), leafDir); |
|
3483 FOREVER |
|
3484 { |
|
3485 TFatDirEntry startEntry; |
|
3486 User::LeaveIfError(GetDirEntry(pos,entry,startEntry,aLongName)); |
|
3487 if (entry.IsEndOfDirectory()) |
|
3488 User::Leave(KErrNotFound); |
|
3489 TBool entryIsVFat=EFalse; |
|
3490 if (startEntry.IsVFatEntry()) |
|
3491 entryIsVFat=ETrue; |
|
3492 if (!entry.IsParentDirectory() && !entry.IsCurrentDirectory() && !entry.IsGarbage() && !entry.IsErased()) |
|
3493 { |
|
3494 TBuf8<0x20> entryName8(DosNameFromStdFormat(entry.Name())); |
|
3495 TBuf<0x20> entryName; |
|
3496 LocaleUtils::ConvertToUnicodeL(entryName, entryName8); |
|
3497 if (shortNameWithoutPathDelimiter.MatchF(entryName)!=KErrNotFound) |
|
3498 { |
|
3499 if (entryIsVFat==EFalse) |
|
3500 aLongName=shortNameWithoutPathDelimiter; |
|
3501 return; |
|
3502 } |
|
3503 } |
|
3504 MoveToNextEntryL(pos); |
|
3505 } |
|
3506 } |
|
3507 |
|
3508 |
|
3509 |
|
3510 //----------------------------------------------------------------------------------------- |
|
3511 |
|
3512 /** |
|
3513 Extend a file or directory, zeroing cluster chain and flushing after every write to FAT. |
|
3514 This method is called for rugged FAT only. |
|
3515 for parameters see CFatTable::ExtendClusterListL |
|
3516 */ |
|
3517 void CFatMountCB::ExtendClusterListZeroedL(TInt aNumber,TInt& aCluster) |
|
3518 { |
|
3519 __PRINT(_L("CFatMountCB::ExtendClusterListZeroedL")); |
|
3520 __ASSERT_DEBUG(aNumber>0,Fault(EFatBadParameter)); |
|
3521 |
|
3522 while(aNumber && FAT().GetNextClusterL(aCluster)) |
|
3523 aNumber--; |
|
3524 |
|
3525 //-- request aNumber free clusters from the FAT, this request may wait until FAT scan thread counted enough free clusters if it is running. |
|
3526 if(!FAT().RequestFreeClusters(aNumber)) |
|
3527 { |
|
3528 __PRINT(_L("CFatMountCB::ExtendClusterListL - leaving KErrDirFull")); |
|
3529 User::Leave(KErrDiskFull); |
|
3530 } |
|
3531 while (aNumber--) |
|
3532 { |
|
3533 TInt freeCluster=FAT().AllocateSingleClusterL(aCluster); |
|
3534 FAT().FlushL(); |
|
3535 ZeroDirClusterL(freeCluster); |
|
3536 FAT().WriteL(aCluster,freeCluster); |
|
3537 FAT().FlushL(); |
|
3538 aCluster=freeCluster; |
|
3539 } |
|
3540 } |
|
3541 |
|
3542 //----------------------------------------------------------------------------------------- |
|
3543 |
|
3544 #if defined(_DEBUG) |
|
3545 TInt CFatMountCB::ControlIO(const RMessagePtr2& aMessage,TInt aCommand,TAny* aParam1,TAny* aParam2) |
|
3546 // |
|
3547 // Debug function |
|
3548 // |
|
3549 { |
|
3550 if(aCommand>=EExtCustom) |
|
3551 { |
|
3552 if(LocalDrive()) |
|
3553 return LocalDrive()->ControlIO(aMessage,aCommand-EExtCustom,aParam1,aParam2); |
|
3554 else |
|
3555 return KErrNotSupported; |
|
3556 } |
|
3557 switch(aCommand) |
|
3558 { |
|
3559 case ECriticalWriteFailOn: |
|
3560 { |
|
3561 TInt r; |
|
3562 TInt16 args[2]; |
|
3563 TPtr8 des((TUint8*)args,4,4); |
|
3564 TRAP(r,aMessage.ReadL(2,des,0)); |
|
3565 if(r!=KErrNone) |
|
3566 return(r); |
|
3567 SetWriteFail(ETrue); |
|
3568 SetWriteFailCount(args[0]); |
|
3569 SetWriteFailError(args[1]); |
|
3570 break; |
|
3571 } |
|
3572 case ECriticalWriteFailOff:SetWriteFail(EFalse);break; |
|
3573 case ERuggedFSysOn: SetRuggedFSys(ETrue);break; |
|
3574 case ERuggedFSysOff: SetRuggedFSys(EFalse);break; |
|
3575 case EIsRuggedFSys: |
|
3576 { |
|
3577 TInt r; |
|
3578 TUint8 val = (IsRuggedFSys()!=0); // val = 0 or 1 for false/true |
|
3579 TPtr8 pVal(&val,1,1); |
|
3580 TRAP(r,aMessage.WriteL(2,pVal,0)); |
|
3581 if(r!=KErrNone) |
|
3582 return(r); |
|
3583 break; |
|
3584 } |
|
3585 case ELocalTimeForRemovableMediaOn: |
|
3586 { |
|
3587 FatFileSystem().SetUseLocalTime(ETrue); |
|
3588 break; |
|
3589 } |
|
3590 case ELocalTimeForRemovableMediaOff: |
|
3591 { |
|
3592 FatFileSystem().SetUseLocalTime(EFalse); |
|
3593 break; |
|
3594 } |
|
3595 case ELocalTimeUsedOnRemovableMedia: |
|
3596 { |
|
3597 TBool flag = FatFileSystem().GetUseLocalTime(); |
|
3598 TPckgC<TBool> flagPckg(flag); |
|
3599 TInt r = aMessage.Write(2, flagPckg); |
|
3600 if(r!=KErrNone) |
|
3601 return r; |
|
3602 break; |
|
3603 } |
|
3604 case ECreationTime: |
|
3605 { |
|
3606 CheckStateConsistentL(); |
|
3607 |
|
3608 TEntryPos firstEntryPos(RootIndicator(),0); |
|
3609 TFatDirEntry firstEntry; |
|
3610 //RFs::ControlIO restricts you to use narrow descriptors |
|
3611 //so convert narrow back to wide. |
|
3612 TBuf8<KMaxPath> fileNameNarrow; |
|
3613 aMessage.Read(2, fileNameNarrow); |
|
3614 |
|
3615 TFileName fileNameWide; |
|
3616 fileNameWide.Copy(fileNameNarrow); |
|
3617 |
|
3618 //find the long file name entry |
|
3619 TRAPD(r, FindEntryStartL(fileNameWide,KEntryAttMaskSupported,firstEntry,firstEntryPos) ); |
|
3620 if(r!=KErrNone) |
|
3621 return(r); |
|
3622 //Find the corresponding 8.3 short name entry, for metadata |
|
3623 MoveToDosEntryL(firstEntryPos,firstEntry); |
|
3624 TTime creationTime=0; |
|
3625 TPckg<TTime> timePckg(creationTime); |
|
3626 SFatDirEntry* sEntry = reinterpret_cast<SFatDirEntry*>(firstEntry.iData); |
|
3627 creationTime = DosTimeToTTime(sEntry->iTimeC, sEntry->iDateC); |
|
3628 r = aMessage.Write(3, timePckg); |
|
3629 if(r!=KErrNone) |
|
3630 return r; |
|
3631 break; |
|
3632 } |
|
3633 case EDisableFATDirCache: |
|
3634 { |
|
3635 MWTCacheInterface* pDirCache = iRawDisk->DirCacheInterface(); |
|
3636 TUint32 KEDisableFATDirCache = CDynamicDirCache::EDisableCache; |
|
3637 pDirCache->Control(KEDisableFATDirCache, (TUint32) aParam1, NULL); |
|
3638 break; |
|
3639 } |
|
3640 case EDumpFATDirCache: |
|
3641 { |
|
3642 MWTCacheInterface* pDirCache = iRawDisk->DirCacheInterface(); |
|
3643 TUint32 KEDumpFATDirCache = CDynamicDirCache::EDumpCache; |
|
3644 pDirCache->Control(KEDumpFATDirCache, 0, NULL); |
|
3645 break; |
|
3646 } |
|
3647 case EFATDirCacheInfo: |
|
3648 { |
|
3649 MWTCacheInterface* pDirCache = iRawDisk->DirCacheInterface(); |
|
3650 TUint32 KEFATDirCacheInfo = CDynamicDirCache::ECacheInfo; |
|
3651 pDirCache->Control(KEFATDirCacheInfo, 0, NULL); |
|
3652 break; |
|
3653 } |
|
3654 |
|
3655 |
|
3656 default: return(KErrNotSupported); |
|
3657 } |
|
3658 return(KErrNone); |
|
3659 } |
|
3660 #else |
|
3661 TInt CFatMountCB::ControlIO(const RMessagePtr2& /*aMessage*/,TInt /*aCommand*/,TAny* /*aParam1*/,TAny* /*aParam2*/) |
|
3662 {return(KErrNotSupported);} |
|
3663 #endif |
|
3664 |
|
3665 |
|
3666 //----------------------------------------------------------------------------------------- |
|
3667 |
|
3668 TInt CFatMountCB::Lock(TMediaPassword& aOld,TMediaPassword& aNew,TBool aStore) |
|
3669 // |
|
3670 // lock media device |
|
3671 // |
|
3672 { |
|
3673 __PRINT(_L("CFatMountCB::Lock")); |
|
3674 TInt r=CreateDrive(Drive().DriveNumber()); |
|
3675 if (r!=KErrNone) |
|
3676 return r; |
|
3677 |
|
3678 TBusLocalDrive* local; |
|
3679 r=LocalDrive()->GetLocalDrive(local); |
|
3680 if (r!=KErrNone) |
|
3681 return r; |
|
3682 |
|
3683 #ifdef _LOCKABLE_MEDIA |
|
3684 if(local->Status()==KErrLocked) |
|
3685 local->Status() = KErrNotReady; |
|
3686 #endif |
|
3687 r=local->SetPassword(aOld,aNew,aStore); |
|
3688 if(r==KErrNone&&aStore) |
|
3689 WritePasswordData(); |
|
3690 return(r); |
|
3691 } |
|
3692 |
|
3693 //----------------------------------------------------------------------------------------- |
|
3694 |
|
3695 TInt CFatMountCB::Unlock(TMediaPassword& aPassword,TBool aStore) |
|
3696 // |
|
3697 // Unlock media device |
|
3698 // |
|
3699 { |
|
3700 __PRINT(_L("CFatMountCB::Unlock")); |
|
3701 TInt r=CreateDrive(Drive().DriveNumber()); |
|
3702 if (r!=KErrNone) |
|
3703 return r; |
|
3704 |
|
3705 TBusLocalDrive* local; |
|
3706 r=LocalDrive()->GetLocalDrive(local); |
|
3707 if (r!=KErrNone) |
|
3708 return r; |
|
3709 |
|
3710 #ifdef _LOCKABLE_MEDIA |
|
3711 if(local->Status()==KErrLocked) |
|
3712 local->Status() = KErrNotReady; |
|
3713 #endif |
|
3714 r=local->Unlock(aPassword,aStore); |
|
3715 if(r==KErrNone&&aStore) |
|
3716 WritePasswordData(); |
|
3717 return(r); |
|
3718 } |
|
3719 |
|
3720 //----------------------------------------------------------------------------------------- |
|
3721 |
|
3722 TInt CFatMountCB::ClearPassword(TMediaPassword& aPassword) |
|
3723 // |
|
3724 // Clear password from media device |
|
3725 // |
|
3726 { |
|
3727 __PRINT(_L("CFatMountCB::ClearPassword")); |
|
3728 TInt r=CreateDrive(Drive().DriveNumber()); |
|
3729 if (r!=KErrNone) |
|
3730 return r; |
|
3731 |
|
3732 TBusLocalDrive* local; |
|
3733 r=LocalDrive()->GetLocalDrive(local); |
|
3734 if (r!=KErrNone) |
|
3735 return r; |
|
3736 |
|
3737 #ifdef _LOCKABLE_MEDIA |
|
3738 if(local->Status()==KErrLocked) |
|
3739 local->Status() = KErrNotReady; |
|
3740 #endif |
|
3741 r=local->Clear(aPassword); |
|
3742 if(r==KErrNone) |
|
3743 WritePasswordData(); |
|
3744 return(r); |
|
3745 } |
|
3746 |
|
3747 //----------------------------------------------------------------------------------------- |
|
3748 |
|
3749 TInt CFatMountCB::ErasePassword() |
|
3750 // |
|
3751 // Forcibly erase the password from a media device |
|
3752 // |
|
3753 { |
|
3754 __PRINT(_L("CFatMountCB::ErasePassword")); |
|
3755 |
|
3756 TInt r=CreateDrive(Drive().DriveNumber()); |
|
3757 if (r!=KErrNone) |
|
3758 return r; |
|
3759 |
|
3760 TBusLocalDrive* local; |
|
3761 r=LocalDrive()->GetLocalDrive(local); |
|
3762 if (r!=KErrNone) |
|
3763 return r; |
|
3764 |
|
3765 #ifdef _LOCKABLE_MEDIA |
|
3766 if(local->Status()==KErrLocked) |
|
3767 local->Status() = KErrNotReady; |
|
3768 #endif |
|
3769 r=local->ErasePassword(); |
|
3770 if(r==KErrNone) |
|
3771 { |
|
3772 // ...media change to ensure a fresh remount the drive |
|
3773 r = local->ForceRemount(0); |
|
3774 local->Status() = KErrNotReady; |
|
3775 WritePasswordData(); |
|
3776 } |
|
3777 return(r); |
|
3778 } |
|
3779 |
|
3780 //----------------------------------------------------------------------------------------- |
|
3781 |
|
3782 TInt CFatMountCB::ForceRemountDrive(const TDesC8* aMountInfo,TInt aMountInfoMessageHandle,TUint aFlags) |
|
3783 // |
|
3784 // Force a remount of the drive |
|
3785 // |
|
3786 { |
|
3787 __PRINT(_L("CFatMountCB::ForceRemountDrive")); |
|
3788 TInt r=CreateDrive(Drive().DriveNumber()); |
|
3789 if (r==KErrNone) |
|
3790 r=LocalDrive()->SetMountInfo(aMountInfo,aMountInfoMessageHandle); |
|
3791 if (r==KErrNone) |
|
3792 r=LocalDrive()->ForceRemount(aFlags); |
|
3793 return(r); |
|
3794 } |
|
3795 |
|
3796 //----------------------------------------------------------------------------------------- |
|
3797 |
|
3798 void CFatMountCB::WritePasswordData() |
|
3799 // |
|
3800 // Write store password data to disk |
|
3801 // |
|
3802 { |
|
3803 __PRINT(_L("CFatMountCB::WritePasswordData")); |
|
3804 TBuf<sizeof(KMediaPWrdFile)> mediaPWrdFile(KMediaPWrdFile); |
|
3805 mediaPWrdFile[0] = (TUint8) RFs::GetSystemDriveChar(); |
|
3806 __PRINT1TEMP(_L("disk file = %S"),mediaPWrdFile); |
|
3807 TBusLocalDrive& local=GetLocalDrive(Drive().DriveNumber()); |
|
3808 TInt length=local.PasswordStoreLengthInBytes(); |
|
3809 if(length==0) |
|
3810 { |
|
3811 WriteToDisk(mediaPWrdFile,_L8("")); |
|
3812 return; |
|
3813 } |
|
3814 HBufC8* hDes=HBufC8::New(length); |
|
3815 if(hDes==NULL) |
|
3816 return; |
|
3817 TPtr8 pDes=hDes->Des(); |
|
3818 TInt r=local.ReadPasswordData(pDes); |
|
3819 if(r==KErrNone) |
|
3820 WriteToDisk(mediaPWrdFile,pDes); |
|
3821 delete hDes; |
|
3822 } |
|
3823 |
|
3824 //----------------------------------------------------------------------------------------- |
|
3825 |
|
3826 /** |
|
3827 Trim trailing spaces of volume label descriptor and adjust its length |
|
3828 */ |
|
3829 void CFatMountCB::TrimVolumeLabel(TDes8& aLabel) const |
|
3830 { |
|
3831 // Locate first '\0' |
|
3832 TInt nullPos = aLabel.Locate('\0'); |
|
3833 if (nullPos == KErrNotFound) |
|
3834 nullPos = KVolumeLabelSize; |
|
3835 |
|
3836 // Trim trailing spaces |
|
3837 TInt i; |
|
3838 for (i=nullPos-1; i>=0; --i) |
|
3839 if (aLabel[i] != 0x20) |
|
3840 break; |
|
3841 aLabel.SetLength(i+1); |
|
3842 } |
|
3843 |
|
3844 //----------------------------------------------------------------------------------------- |
|
3845 |
|
3846 /** |
|
3847 Searches for the volume label file |
|
3848 |
|
3849 @param aLabel The name of the volume label file returned upon successful search |
|
3850 @return KErrNone if it finds the volume label file, otherwise KErrNotFound |
|
3851 */ |
|
3852 TInt CFatMountCB::ReadVolumeLabelFile(TDes8& aLabel) |
|
3853 { |
|
3854 __PRINT(_L("+CFatMountCB::ReadVolumeLabelFile")); |
|
3855 TEntryPos pos(RootIndicator(),0); |
|
3856 TFatDirEntry entry; |
|
3857 TRAPD(r, FindVolumeLabelFileL(aLabel, pos, entry)); |
|
3858 __PRINT1(_L("-CFatMountCB::ReadVolumeLabelFile: %d"),r); |
|
3859 return r; |
|
3860 } |
|
3861 |
|
3862 //----------------------------------------------------------------------------------------- |
|
3863 |
|
3864 /** |
|
3865 Creates or updates the volume label file with name aNewName |
|
3866 |
|
3867 @param aNewName The new name for the volume label file |
|
3868 */ |
|
3869 void CFatMountCB::WriteVolumeLabelFileL(const TDesC8& aNewName) |
|
3870 { |
|
3871 __PRINT1(_L("+CFatMountCB::WriteVolumeLabelFileL: [%S]"), &aNewName); |
|
3872 TEntryPos pos(RootIndicator(),0); |
|
3873 TFatDirEntry entry; |
|
3874 |
|
3875 TBuf8<KVolumeLabelSize> oldName; |
|
3876 TRAPD(r, FindVolumeLabelFileL(oldName, pos, entry)); |
|
3877 |
|
3878 if( KErrNone == r ) |
|
3879 { |
|
3880 // Found existing volume label file, rename or delete |
|
3881 if(oldName == aNewName) |
|
3882 { |
|
3883 __PRINT(_L("-CFatMountCB::WriteVolumeLabelFileL: found: names match")); |
|
3884 return; |
|
3885 } |
|
3886 else |
|
3887 { |
|
3888 if(aNewName.Length() == 0) |
|
3889 { |
|
3890 // delete the volume label file |
|
3891 __PRINT(_L("CFatMountCB::WriteVolumeLabelFileL: found: delete")); |
|
3892 EraseDirEntryL(pos, entry); |
|
3893 } |
|
3894 else |
|
3895 { |
|
3896 __PRINT(_L("CFatMountCB::WriteVolumeLabelFileL: found: replace")); |
|
3897 entry.SetName(aNewName); |
|
3898 WriteDirEntryL(pos, entry); |
|
3899 } |
|
3900 FAT().FlushL(); |
|
3901 } |
|
3902 } |
|
3903 else if( KErrNotFound == r ) |
|
3904 { |
|
3905 // Not found, need to create if aNewName is not empty |
|
3906 // Windows allows a volume label file to have the same name as |
|
3907 // an existing file or directory |
|
3908 if(aNewName.Length() > 0) |
|
3909 { |
|
3910 __PRINT(_L("CFatMountCB::WriteVolumeLabelFileL: not found: create")); |
|
3911 TEntryPos dirPos(RootIndicator(),0); |
|
3912 AddDirEntryL(dirPos,1); |
|
3913 TFatDirEntry fatDirEntry; |
|
3914 fatDirEntry.SetName(aNewName); |
|
3915 fatDirEntry.SetAttributes(KEntryAttVolume); |
|
3916 |
|
3917 TTime now; |
|
3918 now.UniversalTime(); |
|
3919 fatDirEntry.SetTime(now, TimeOffset() ); |
|
3920 fatDirEntry.SetStartCluster(0); |
|
3921 fatDirEntry.SetSize(0); |
|
3922 WriteDirEntryL(dirPos, fatDirEntry); |
|
3923 FAT().FlushL(); |
|
3924 } |
|
3925 } |
|
3926 else |
|
3927 { |
|
3928 // Some other error |
|
3929 User::Leave(r); |
|
3930 } |
|
3931 } |
|
3932 |
|
3933 |
|
3934 //----------------------------------------------------------------------------------------- |
|
3935 |
|
3936 /** |
|
3937 Scans the root directory for a volume label file. Leaves with an error if not found |
|
3938 |
|
3939 @param aLabel Name of the volume label file upon successful search |
|
3940 @param aDosEntryPos Pointer to position of the volume label file upon successful search |
|
3941 @param aDosEntry Contains the entry for the volume label file upon successful search |
|
3942 */ |
|
3943 void CFatMountCB::FindVolumeLabelFileL(TDes8& aLabel, TEntryPos& aDosEntryPos, TFatDirEntry& aDosEntry) |
|
3944 { |
|
3945 __PRINT(_L("+CFatMountCB::FindVolumeLabelFileL")); |
|
3946 |
|
3947 if(IsRootDir(aDosEntryPos) && (aDosEntryPos.iPos+StartOfRootDirInBytes()>=RootDirEnd())) |
|
3948 { |
|
3949 __PRINT(_L("-CFatMountCB::FindVolumeLabelFileL: abort, exceeds root")); |
|
3950 User::Leave(KErrNotFound); // Allows maximum number of entries in root directory |
|
3951 } |
|
3952 |
|
3953 TInt previousCluster= aDosEntryPos.iCluster; |
|
3954 TUint previousPosition= aDosEntryPos.iPos; |
|
3955 TInt changePreviousCluster=1; |
|
3956 TInt count=0; |
|
3957 |
|
3958 TFatDirEntry startEntry; |
|
3959 TFileName dummyLongName; |
|
3960 |
|
3961 FOREVER |
|
3962 { |
|
3963 #ifdef _DEBUG |
|
3964 const TInt e= GetDirEntry(aDosEntryPos, aDosEntry, startEntry, dummyLongName); |
|
3965 __PRINT1(_L("CFatMountCB::FindVolumeLabelFileL: GetDir %d"), e); |
|
3966 User::LeaveIfError(e); |
|
3967 #else |
|
3968 User::LeaveIfError(GetDirEntry(aDosEntryPos, aDosEntry, startEntry, dummyLongName)); |
|
3969 #endif |
|
3970 if(aDosEntry.IsEndOfDirectory()) |
|
3971 { |
|
3972 __PRINT(_L("-CFatMountCB::FindVolumeLabelFileL: end of dir")); |
|
3973 User::Leave(KErrNotFound); |
|
3974 } |
|
3975 if(IsRootDir(aDosEntryPos) && (aDosEntryPos.iPos+StartOfRootDirInBytes()==(RootDirEnd()-KSizeOfFatDirEntry))) |
|
3976 { |
|
3977 if(aDosEntry.IsErased()) |
|
3978 { |
|
3979 __PRINT(_L("-CFatMountCB::FindVolumeLabelFileL: erased end of root")); |
|
3980 User::Leave(KErrNotFound); //Allows maximum number of entries in root directory |
|
3981 } |
|
3982 } |
|
3983 if(!aDosEntry.IsCurrentDirectory() && !aDosEntry.IsParentDirectory() && !aDosEntry.IsErased() && !aDosEntry.IsGarbage()) |
|
3984 { |
|
3985 if(aDosEntry.Attributes() & KEntryAttVolume) |
|
3986 { |
|
3987 aLabel = aDosEntry.Name(); |
|
3988 #ifdef _DEBUG |
|
3989 dummyLongName.Copy(aLabel); |
|
3990 __PRINT1(_L("-CFatMountCB::FindVolumeLabelFileL: found [%S]"), &dummyLongName); |
|
3991 #endif |
|
3992 break; |
|
3993 } |
|
3994 } |
|
3995 MoveToNextEntryL(aDosEntryPos); |
|
3996 if(IsRootDir(aDosEntryPos) && (aDosEntryPos.iPos+StartOfRootDirInBytes()>=RootDirEnd())) |
|
3997 { |
|
3998 __PRINT(_L("-CFatMountCB::FindVolumeLabelFileL: passed end of root")); |
|
3999 User::Leave(KErrNotFound); //Allows maximum number of entries in root directory |
|
4000 } |
|
4001 if(aDosEntryPos.iCluster && (aDosEntryPos.iPos <= previousPosition)) |
|
4002 { |
|
4003 DoCheckFatForLoopsL(aDosEntryPos.iCluster, previousCluster, changePreviousCluster, count); |
|
4004 } |
|
4005 previousPosition=aDosEntryPos.iPos; |
|
4006 } |
|
4007 } |
|
4008 |
|
4009 //----------------------------------------------------------------------------------------- |
|
4010 |
|
4011 /** |
|
4012 Read volume label from disk and trim trailing 0x20 & 0x00 characters |
|
4013 */ |
|
4014 void CFatMountCB::GetVolumeLabelFromDiskL(const TFatBootSector& aBootSector) |
|
4015 { |
|
4016 // Read volume label as 8 bit descriptor |
|
4017 TBuf8<KVolumeLabelSize> volName8; |
|
4018 TInt r = ReadVolumeLabelFile(volName8); |
|
4019 if(r != KErrNone) // No volume label file in root directory |
|
4020 volName8 = aBootSector.VolumeLabel(); |
|
4021 TrimVolumeLabel(volName8); |
|
4022 |
|
4023 TBuf16<KVolumeLabelSize> volName16; |
|
4024 LocaleUtils::ConvertToUnicodeL(volName16, volName8); |
|
4025 SetVolumeName(volName16.AllocL()); |
|
4026 } |
|
4027 |
|
4028 |
|
4029 //----------------------------------------------------------------------------------------- |
|
4030 |
|
4031 /** |
|
4032 Populates iMap member of aInfo with contiguous block group maps. |
|
4033 |
|
4034 @param aPos Start position for a desired section of the file. |
|
4035 @param sLength Length of the desired data to produce the block map for. |
|
4036 @param aInfo A structure describing a group of block maps. |
|
4037 */ |
|
4038 void CFatMountCB::BlockMapReadFromClusterListL(TEntryPos& aPos, TInt aLength, SBlockMapInfo& aInfo) |
|
4039 { |
|
4040 __PRINT(_L("CFatMountCB::BlockMapReadFromClusterListL")); |
|
4041 __ASSERT_ALWAYS(aPos.Cluster()>=KFatFirstSearchCluster,User::Leave(KErrCorrupt)); |
|
4042 TBlockMapEntry blockMapEntry; |
|
4043 |
|
4044 TUint i = 0; |
|
4045 TInt clusterRelativePos; |
|
4046 TInt maxClusters; |
|
4047 TInt endCluster; |
|
4048 TInt clusterListLen; |
|
4049 TInt readLength; |
|
4050 TInt temp; |
|
4051 TInt currentPos; |
|
4052 TLocalDriveCapsBuf caps; |
|
4053 TInt r; |
|
4054 TInt64 realPosition = 0; |
|
4055 |
|
4056 do |
|
4057 { |
|
4058 currentPos = aPos.iPos; |
|
4059 temp = currentPos>>ClusterSizeLog2(); |
|
4060 if ( (currentPos) && ( (currentPos) == (temp<<ClusterSizeLog2()) ) ) |
|
4061 { |
|
4062 if (!FAT().GetNextClusterL(aPos.iCluster)) |
|
4063 { |
|
4064 __PRINT(_L("CFatMountCB::BlockMapReadFromClusterListL corrupt#1")) |
|
4065 User::Leave(KErrCorrupt); |
|
4066 } |
|
4067 } |
|
4068 clusterRelativePos = ClusterRelativePos( aPos.iPos ); |
|
4069 maxClusters = ((aLength + clusterRelativePos - 1)>>ClusterSizeLog2())+1; |
|
4070 clusterListLen = FAT().CountContiguousClustersL(aPos.iCluster, endCluster, maxClusters); |
|
4071 readLength = Min( aLength, (clusterListLen<<ClusterSizeLog2()) - clusterRelativePos); |
|
4072 |
|
4073 blockMapEntry.SetNumberOfBlocks( clusterListLen ); |
|
4074 if (aPos.iCluster < 2) |
|
4075 User::Leave(KErrCorrupt); |
|
4076 r = LocalDrive()->Caps(caps); |
|
4077 if ( r != KErrNone ) |
|
4078 User::LeaveIfError(r); |
|
4079 if ( caps().iType&EMediaRam ) |
|
4080 { |
|
4081 realPosition = FAT().DataPositionInBytes( aPos.iCluster ); |
|
4082 aPos.iCluster = I64LOW((realPosition - aInfo.iStartBlockAddress)>>ClusterSizeLog2()); |
|
4083 blockMapEntry.SetStartBlock( aPos.iCluster ); |
|
4084 } |
|
4085 else |
|
4086 blockMapEntry.SetStartBlock( aPos.iCluster - 2); |
|
4087 aInfo.iMap.Append(TPckgC<TBlockMapEntry>(blockMapEntry)); |
|
4088 aPos.iPos += readLength; |
|
4089 aPos.iCluster = endCluster; |
|
4090 aLength -= readLength; |
|
4091 } |
|
4092 while( ( aLength > 0 ) && ( ++i < KMaxMapsPerCall ) ); |
|
4093 } |
|
4094 |
|
4095 |
|
4096 //----------------------------------------------------------------------------------------- |
|
4097 |
|
4098 TInt CFatMountCB::GetDosEntryFromNameL(const TDesC& aName, TEntryPos& aDosEntryPos, TFatDirEntry& aDosEntry) |
|
4099 { |
|
4100 TFatDirEntry firstEntry; |
|
4101 TEntryPos firstEntryPos(RootIndicator(),0); // Already checked entry is a directory |
|
4102 FindEntryStartL(aName,KEntryAttMaskSupported,firstEntry,firstEntryPos); |
|
4103 |
|
4104 aDosEntryPos=firstEntryPos; |
|
4105 aDosEntry=firstEntry; |
|
4106 MoveToDosEntryL(aDosEntryPos,aDosEntry); |
|
4107 |
|
4108 return KErrNone; |
|
4109 } |
|
4110 |
|
4111 //----------------------------------------------------------------------------------------- |
|
4112 |
|
4113 TInt CFatMountCB::GetFileUniqueId(const TDesC& aName, TInt64& aUniqueId) |
|
4114 { |
|
4115 // Get first cluster of file |
|
4116 TEntryPos dosEntryPos(RootIndicator(),0); |
|
4117 TFatDirEntry dosEntry; |
|
4118 InitializeRootEntry(dosEntry); // Nugatory initialisation to placate warnings |
|
4119 TRAPD(err,GetDosEntryFromNameL(aName,dosEntryPos,dosEntry)); |
|
4120 if(err!=KErrNone) |
|
4121 return err; |
|
4122 TInt startCluster=StartCluster(dosEntry); |
|
4123 // Empty files will return a cluster of zero |
|
4124 if(startCluster==0) |
|
4125 return KErrEof; |
|
4126 aUniqueId=MAKE_TINT64(0,startCluster); |
|
4127 return KErrNone; |
|
4128 } |
|
4129 //----------------------------------------------------------------------------------------- |
|
4130 |
|
4131 |
|
4132 TInt CFatMountCB::Spare3(TInt /*aVal*/, TAny* /*aPtr1*/, TAny* /*aPtr2*/) |
|
4133 { |
|
4134 return KErrNotSupported; |
|
4135 } |
|
4136 |
|
4137 TInt CFatMountCB::Spare2(TInt /*aVal*/, TAny* /*aPtr1*/, TAny* /*aPtr2*/) |
|
4138 { |
|
4139 return KErrNotSupported; |
|
4140 } |
|
4141 |
|
4142 TInt CFatMountCB::Spare1(TInt /*aVal*/, TAny* /*aPtr1*/, TAny* /*aPtr2*/) |
|
4143 { |
|
4144 return KErrNotSupported; |
|
4145 } |
|
4146 |
|
4147 //----------------------------------------------------------------------------------------- |
|
4148 |
|
4149 //-- maximal level of recursion for the CheckDisk. i.e. the max. number of folded directories to check. |
|
4150 const TInt KCheckDskMaxRecursionLevel = 50; |
|
4151 |
|
4152 // |
|
4153 // Walks a directory cluster list then checks all the entries. |
|
4154 // |
|
4155 void CFatMountCB::ChkDirL(RBitVector& aFatBitVec, TInt aDirCluster) |
|
4156 { |
|
4157 //__PRINT1(_L("### CFatMountCB::ChkDirL() level:%d"),iChkDiscRecLevel); |
|
4158 |
|
4159 //-- check if we have reached the recursion limit. on hardware the stack is very limited |
|
4160 //-- and its overflow will lead to crash. |
|
4161 if(iChkDiscRecLevel++ >= KCheckDskMaxRecursionLevel) |
|
4162 { |
|
4163 __PRINT1(_L("CFatMountCB::ChkDirL() max recursion level(%d) reached. Leaving!"),iChkDiscRecLevel); |
|
4164 User::Leave(KErrTooBig); |
|
4165 } |
|
4166 |
|
4167 if(/*Is32BitFat() &&*/aDirCluster != 0 && (aDirCluster == RootIndicator()))//the bit in comments maybe required |
|
4168 WalkClusterListL(aFatBitVec, RootIndicator()); |
|
4169 |
|
4170 TEntryPos entryPos(aDirCluster,0); |
|
4171 FOREVER |
|
4172 { |
|
4173 TFatDirEntry entry; |
|
4174 ReadDirEntryL(entryPos,entry); |
|
4175 MoveToDosEntryL(entryPos,entry); |
|
4176 if (entry.IsEndOfDirectory()) |
|
4177 break; |
|
4178 if (IsRootDir(entryPos)&&(StartOfRootDirInBytes()+entryPos.iPos==(RootDirEnd()-KSizeOfFatDirEntry))) |
|
4179 { |
|
4180 if(!entry.IsErased()) |
|
4181 ChkEntryL(aFatBitVec, entry); |
|
4182 break; // Allows maximum number of entries in root directory |
|
4183 } |
|
4184 MoveToNextEntryL(entryPos); |
|
4185 if (entry.IsParentDirectory() || entry.IsCurrentDirectory() || entry.IsErased()) |
|
4186 continue; |
|
4187 ChkEntryL(aFatBitVec, entry); |
|
4188 } |
|
4189 |
|
4190 iChkDiscRecLevel--; |
|
4191 } |
|
4192 |
|
4193 //----------------------------------------------------------------------------------------- |
|
4194 |
|
4195 // |
|
4196 // Check FAT is valid for anEntry |
|
4197 // |
|
4198 void CFatMountCB::ChkEntryL(RBitVector& aFatBitVec, const TFatDirEntry& anEntry) |
|
4199 { |
|
4200 TInt listLength=0; |
|
4201 |
|
4202 if ((anEntry.Attributes()&(KEntryAttDir)) || anEntry.Size()) |
|
4203 listLength=WalkClusterListL(aFatBitVec, StartCluster(anEntry)); |
|
4204 else if (anEntry.StartCluster() != 0) // zero length file |
|
4205 User::Leave(EFatChkDskInvalidEntrySize); // shouldn't have clusters |
|
4206 |
|
4207 if (anEntry.Attributes()&KEntryAttDir) |
|
4208 ChkDirL(aFatBitVec, StartCluster(anEntry)); |
|
4209 |
|
4210 // Check that the correct number of clusters have been allocated for the size of the file. |
|
4211 |
|
4212 else if ((anEntry.Attributes()&KEntryAttVolume)==0) |
|
4213 { |
|
4214 TInt clustersForFileSize; |
|
4215 TInt clusterSize=1<<ClusterSizeLog2(); |
|
4216 clustersForFileSize = (TInt) ( (TInt64(anEntry.Size()) + TInt64(clusterSize-1)) >> ClusterSizeLog2() ); |
|
4217 |
|
4218 if (listLength!=clustersForFileSize) |
|
4219 User::Leave(EFatChkDskInvalidEntrySize); |
|
4220 } |
|
4221 } |
|
4222 |
|
4223 //----------------------------------------------------------------------------------------- |
|
4224 |
|
4225 // |
|
4226 // Walks cluster list from aCluster to EOF |
|
4227 // Reports an error if an invalid cluster is found before EOF or |
|
4228 // a cluster has been visited before. |
|
4229 // |
|
4230 TInt CFatMountCB::WalkClusterListL(RBitVector& aFatBitVec, TInt aCluster) |
|
4231 { |
|
4232 |
|
4233 TInt i=0; |
|
4234 do { |
|
4235 i++; |
|
4236 if (!ValidClusterNumber(aCluster)) |
|
4237 { |
|
4238 __PRINT1(_L("Bad Cluster number %d"),aCluster); |
|
4239 User::Leave(EFatChkDskIllegalClusterNumber); |
|
4240 } |
|
4241 |
|
4242 if (IsClusterVisited(aFatBitVec, aCluster)) |
|
4243 { |
|
4244 __PRINT1(_L("Cluster already in use %d"),aCluster); |
|
4245 User::Leave(EFatChkDskClusterAlreadyInUse); |
|
4246 } |
|
4247 |
|
4248 MarkClusterVisited(aFatBitVec, aCluster); |
|
4249 |
|
4250 } while (FAT().GetNextClusterL(aCluster)); |
|
4251 |
|
4252 return(i); |
|
4253 } |
|
4254 |
|
4255 //----------------------------------------------------------------------------------------- |
|
4256 |
|
4257 // |
|
4258 // Checks that all unvisited clusters are marked as free in the FAT |
|
4259 // |
|
4260 void CFatMountCB::CheckUnvisitedClustersL(const RBitVector& aFatBitVec) const |
|
4261 { |
|
4262 |
|
4263 TInt cluster=2; |
|
4264 TInt maxCluster=cluster + UsableClusters(); |
|
4265 while (cluster<maxCluster) |
|
4266 { |
|
4267 cluster=NextUnvisitedCluster(aFatBitVec, cluster); //-- move to the next unvisited cluster |
|
4268 if(cluster < 0 || cluster >= maxCluster) |
|
4269 break; |
|
4270 |
|
4271 TInt clusterVal=FAT().ReadL(cluster); |
|
4272 if (clusterVal!=0 && IsEndOfClusterCh(clusterVal)==EFalse && !IsBadCluster(clusterVal)) |
|
4273 { |
|
4274 __PRINT1(_L("\n*****Bad cluster Num = %d"),cluster); |
|
4275 User::Leave(EFatChkDskBadCluster); |
|
4276 } |
|
4277 } |
|
4278 } |
|
4279 |
|
4280 //----------------------------------------------------------------------------------------- |
|
4281 |
|
4282 /** |
|
4283 @param aCluster cluster number to check for validity |
|
4284 @returns ETrue if aCluster is a valid cluster number |
|
4285 */ |
|
4286 TBool CFatMountCB::ValidClusterNumber(TUint32 aCluster) const |
|
4287 { |
|
4288 return (aCluster>=KFatFirstSearchCluster && aCluster<=MaxClusterNumber()); |
|
4289 } |
|
4290 |
|
4291 //----------------------------------------------------------------------------------------- |
|
4292 |
|
4293 // |
|
4294 // Walk the FAT, returns error if find an unterminated list or |
|
4295 // lists that merge. |
|
4296 // |
|
4297 TInt CFatMountCB::CheckDisk() |
|
4298 { |
|
4299 |
|
4300 __PRINT1(_L("CFatMountCB::CheckDisk() drv:%d"), DriveNumber()); |
|
4301 |
|
4302 if(!ConsistentState()) |
|
4303 return KErrCorrupt; |
|
4304 |
|
4305 //-- create a bit representation of the FAT |
|
4306 const TUint32 MaxClusters = UsableClusters()+KFatFirstSearchCluster; //-- UsableClusters() doesn't count first 2 unused clusers |
|
4307 |
|
4308 |
|
4309 // cluster count may be zero if boot sector failed to be read (e.g. if the media is locked) |
|
4310 // or if TDrive::MountMedia(ETrue) has been called (in which case the boot sector may |
|
4311 if (MaxClusters == 0) |
|
4312 return KErrCorrupt; |
|
4313 |
|
4314 RBitVector bitVec; //-- each bit in this vector represents a FAT cluster |
|
4315 |
|
4316 TInt nRes = bitVec.Create(MaxClusters); |
|
4317 if(nRes != KErrNone) |
|
4318 { |
|
4319 ASSERT(nRes == KErrNoMemory); //-- the only one possible reason. |
|
4320 return KErrNoMemory; |
|
4321 } |
|
4322 |
|
4323 iChkDiscRecLevel = 0; //-- reset CheckDisk recursion counter |
|
4324 TRAPD(r,ChkDirL(bitVec, RootIndicator())); // Check from root directory |
|
4325 if (r==KErrNone) |
|
4326 { |
|
4327 TRAP(r,CheckUnvisitedClustersL(bitVec)); |
|
4328 } |
|
4329 |
|
4330 |
|
4331 bitVec.Close(); |
|
4332 |
|
4333 switch(r) |
|
4334 { |
|
4335 |
|
4336 case KErrNone: |
|
4337 return KErrNone; |
|
4338 |
|
4339 case EFatChkDskIllegalClusterNumber: |
|
4340 return(1); |
|
4341 |
|
4342 case EFatChkDskClusterAlreadyInUse: |
|
4343 return(2); |
|
4344 |
|
4345 case EFatChkDskBadCluster: |
|
4346 return(3); |
|
4347 |
|
4348 case EFatChkDskInvalidEntrySize: |
|
4349 return(4); |
|
4350 |
|
4351 default: |
|
4352 break; |
|
4353 } |
|
4354 |
|
4355 return(r); |
|
4356 } |
|
4357 |
|
4358 |
|
4359 //----------------------------------------------------------------------------------------- |
|
4360 // Helper functions for Check Disk functionality |
|
4361 //----------------------------------------------------------------------------------------- |
|
4362 |
|
4363 /** |
|
4364 Find the next unvisited cluster number in the bit array. |
|
4365 |
|
4366 @param aBitList bit array, where '0' bits represent unvisited clusters. |
|
4367 @param aCluster cluster number to start search with. |
|
4368 |
|
4369 @return positive integer indicating next unvisited cluster number |
|
4370 KErrNotFound (-1) if there are no unvisited clusters |
|
4371 |
|
4372 */ |
|
4373 static TInt NextUnvisitedCluster(const RBitVector& aFatBitVec, TUint32 aCluster) |
|
4374 { |
|
4375 __ASSERT_DEBUG(aCluster >= KFatFirstSearchCluster, Fault(EFatChkDskIllegalClusterNumber)); //-- 1st 2 FAT entries are reserved |
|
4376 |
|
4377 TUint32 searchPos = aCluster; //-- bit number to start search with |
|
4378 |
|
4379 //-- look for the unvisited cluster (bit '0') in the bit array from the searchPos to the right |
|
4380 if(aFatBitVec.Find(searchPos, 0, RBitVector::ERight)) |
|
4381 return searchPos; |
|
4382 |
|
4383 return KErrNotFound; |
|
4384 } |
|
4385 |
|
4386 |
|
4387 /** |
|
4388 Check if we have visited cluster aCluster |
|
4389 |
|
4390 @param aFatBitVec bit array, where '0' bits represent unvisited clusters. |
|
4391 @param aCluster cluster number to check |
|
4392 @return ETrue if aCluster has been visited. |
|
4393 */ |
|
4394 static TBool IsClusterVisited(const RBitVector& aFatBitVec, TUint32 aCluster) |
|
4395 { |
|
4396 __ASSERT_DEBUG(aCluster >= KFatFirstSearchCluster, Fault(EFatChkDskIllegalClusterNumber)); //-- 1st 2 FAT entries are reserved |
|
4397 |
|
4398 return aFatBitVec[aCluster]; |
|
4399 } |
|
4400 |
|
4401 /** |
|
4402 Mark aCluster as visited |
|
4403 @param aFatBitVec bit array, where '0' bits represent unvisited clusters. |
|
4404 @param aCluster cluster number to mark |
|
4405 */ |
|
4406 static void MarkClusterVisited(RBitVector& aFatBitVec, TUint32 aCluster) |
|
4407 { |
|
4408 __ASSERT_DEBUG(aCluster >= KFatFirstSearchCluster, Fault(EFatChkDskIllegalClusterNumber)); //-- 1st 2 FAT entries are reserved |
|
4409 |
|
4410 aFatBitVec.SetBit(aCluster); //-- '1' bit in a bit array means that the corresponding cluster is visited |
|
4411 } |
|
4412 |
|
4413 |
|
4414 |
|
4415 //------------------------------------------------------------------------------------------------------------------- |
|
4416 |
|
4417 /** |
|
4418 Creates a scan drive object and starts the scan. |
|
4419 */ |
|
4420 TInt CFatMountCB::DoRunScanDrive() |
|
4421 { |
|
4422 TInt nRes; |
|
4423 |
|
4424 CScanDrive* pScnDrv = NULL; |
|
4425 TRAP(nRes, pScnDrv=CScanDrive::NewL(this)); |
|
4426 if(nRes != KErrNone) |
|
4427 return nRes; |
|
4428 |
|
4429 TRAPD(nScnDrvRes, pScnDrv->StartL()); |
|
4430 |
|
4431 const TBool bNeedFatRemount = (nScnDrvRes!=KErrNone) || pScnDrv->ProblemsDiscovered(); |
|
4432 delete pScnDrv; |
|
4433 |
|
4434 |
|
4435 if(bNeedFatRemount) |
|
4436 {//-- ScanDrive found and probably fixed some errors. |
|
4437 // ensure cached fat and free cluster count are updated |
|
4438 DoDismount(); //-- dismount |
|
4439 TRAP(nRes, MountL(EFalse)); //-- mount again |
|
4440 } |
|
4441 |
|
4442 if(nScnDrvRes != KErrNone) |
|
4443 return nScnDrvRes; |
|
4444 |
|
4445 |
|
4446 //-- if ScanDrive hasn't found anything wrong or has fixed recoverable erros, mark the volume clean |
|
4447 if(VolCleanFlagSupported()) |
|
4448 { |
|
4449 //-- if there is a background FAT scanning thread, we need to wait until it finishes its work. |
|
4450 //-- otherwise it's possible to have incorrect amount of free space on the volume until next remounting. |
|
4451 (void)FAT().NumberOfFreeClusters(ETrue); |
|
4452 TRAP(nRes, FinaliseMountL()); |
|
4453 ASSERT(nRes == KErrNone); |
|
4454 } |
|
4455 |
|
4456 return KErrNone; |
|
4457 } |
|
4458 |
|
4459 //------------------------------------------------------------------------------------------------------------------- |
|
4460 |
|
4461 /** |
|
4462 Run scan drive on the given volume. |
|
4463 The ScanDrive may be skipped on the finalised volumes, i.e. those, that had been shut down properly. |
|
4464 |
|
4465 |
|
4466 @return Either KErrCorrupt if an error was found that is not caused by write failure due to power removal. |
|
4467 KErrNone if no error was found. One of four positive codes explaining what type of error was rectified |
|
4468 */ |
|
4469 TInt CFatMountCB::ScanDrive() |
|
4470 { |
|
4471 __PRINT1(_L("CFatMountCB::ScanDrive() starting on drive %d"), DriveNumber()); |
|
4472 |
|
4473 if(!ConsistentState()) |
|
4474 return KErrCorrupt; |
|
4475 |
|
4476 TInt nRes; |
|
4477 |
|
4478 if(LockStatus()!=0) |
|
4479 { |
|
4480 __PRINT(_L("CFatMountCB::ScanDrive() locked!\n")); |
|
4481 return KErrInUse; |
|
4482 } |
|
4483 |
|
4484 if(iRamDrive) |
|
4485 {//-- Do not check internal RAM drive |
|
4486 __PRINT(_L("CFatMountCB::ScanDrive() Skipping Internal RAM drive.")); |
|
4487 return KErrNone; |
|
4488 } |
|
4489 |
|
4490 //-- check if the volume is finalised and skip running ScanDrive if this option is enabled in estart.txt |
|
4491 if(VolCleanFlagSupported() && FatConfig().ScanDrvSkipFinalisedVolume()) |
|
4492 { |
|
4493 TBool bVolClean = EFalse; |
|
4494 TRAP(nRes, bVolClean = VolumeCleanL()); |
|
4495 |
|
4496 if(nRes == KErrNone && bVolClean) |
|
4497 { |
|
4498 __PRINT(_L("Skipping ScanDrive on finalised volume!")); |
|
4499 return KErrNone; //-- skip ScanDrive on a clean volume |
|
4500 } |
|
4501 } |
|
4502 |
|
4503 //-- run ScanDrive |
|
4504 nRes = Open(); |
|
4505 if(nRes != KErrNone) |
|
4506 return nRes; |
|
4507 |
|
4508 nRes = DoRunScanDrive(); |
|
4509 |
|
4510 Close(); |
|
4511 |
|
4512 __PRINT2(_L("~ CFatMountCB::ScanDrive() finished for drive %d with the code %d"),DriveNumber(), nRes); |
|
4513 |
|
4514 return nRes; |
|
4515 |
|
4516 } |
|
4517 |
|
4518 //----------------------------------------------------------------------------------------- |
|
4519 /** |
|
4520 Returns the offset between UTC time and timestamps on the filesystem. This will return User::UTCOffset |
|
4521 if the flag iUseLocalTime has been set in CFatFileSystem and this mount is on a removable drive. If not |
|
4522 a null offset is returned. |
|
4523 |
|
4524 @return The offset in seconds that timestamps on the filesystem have, relative to UTC. |
|
4525 */ |
|
4526 TTimeIntervalSeconds CFatMountCB::TimeOffset() const |
|
4527 { |
|
4528 if((Drive().Att() & KDriveAttRemovable) && FatFileSystem().GetUseLocalTime() ) |
|
4529 { |
|
4530 return User::UTCOffset(); |
|
4531 } |
|
4532 else |
|
4533 { |
|
4534 return TTimeIntervalSeconds(0); |
|
4535 } |
|
4536 } |
|
4537 |
|
4538 |
|
4539 |
|
4540 |
|
4541 //----------------------------------------------------------------------------------------- |
|
4542 /** |
|
4543 Check is this file system can be mounted on the drive at all. |
|
4544 Just read and validate boot region, no real mounting overhead. |
|
4545 |
|
4546 @return KErrNone boot region is OK, the file system can be mounted. |
|
4547 KErrLocked the media is locked on a physical level. |
|
4548 other error codes depending on the implementation |
|
4549 |
|
4550 */ |
|
4551 TInt CFatMountCB::MntCtl_DoCheckFileSystemMountable() |
|
4552 { |
|
4553 TInt nRes; |
|
4554 |
|
4555 const TInt driveNo = Drive().DriveNumber(); |
|
4556 __PRINT1(_L("CFatMountCB::MntCtl_DoCheckFileSystemMountable() drv:%d"),driveNo); |
|
4557 |
|
4558 nRes = CreateDrive(driveNo); |
|
4559 if(nRes != KErrNone) |
|
4560 { |
|
4561 __PRINT1(_L(" ..CreateDrive() err:%d \n"), nRes); |
|
4562 return nRes; |
|
4563 } |
|
4564 |
|
4565 //-- try reading boot sector. This doesn't require iDriverInterface setup, it uses LocalDrive() |
|
4566 TFatBootSector bootSector; |
|
4567 nRes = ReadBootSector(bootSector); |
|
4568 |
|
4569 DismountedLocalDrive(); |
|
4570 |
|
4571 return nRes; |
|
4572 } |
|
4573 |
|
4574 |
|
4575 |