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