1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/userlibandfileserver/fileserver/sfat32/sl_scan32.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1193 @@
1.4 +// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// f32\sfat32\sl_scan32.cpp
1.18 +// ScanDrive code, specific for EFAT32.FSY
1.19 +//
1.20 +//
1.21 +
1.22 +/**
1.23 + @file
1.24 + @internalTechnology
1.25 +*/
1.26 +
1.27 +#include "sl_std.h"
1.28 +#include "sl_scandrv.h"
1.29 +
1.30 +const TInt KMaxScanDepth = 20; ///< Maximum scan depth of to avoid stack over flow
1.31 +const TInt KClusterListGranularity = 8; ///< Granularity of cluster list used for storage of clusters when KMaxScanDepth is reached
1.32 +
1.33 +
1.34 +
1.35 +/**
1.36 + CScanDrive factory method
1.37 + @param aMount the owning mount
1.38 +*/
1.39 +CScanDrive* CScanDrive::NewL(CFatMountCB* aMount)
1.40 + {
1.41 + if(!aMount)
1.42 + {
1.43 + ASSERT(0);
1.44 + User::Leave(KErrArgument);
1.45 + }
1.46 +
1.47 + CScanDrive* self=new (ELeave) CScanDrive();
1.48 + CleanupStack::PushL(self);
1.49 + self->ConstructL(aMount);
1.50 + CleanupStack::Pop();
1.51 +
1.52 + return self;
1.53 + }
1.54 +
1.55 +
1.56 +CScanDrive::~CScanDrive()
1.57 + {
1.58 + for(TUint i=0; i<KMaxArrayDepth && iClusterListArray[i]!=NULL; ++i)
1.59 + {
1.60 + iClusterListArray[i]->Close();
1.61 + delete iClusterListArray[i];
1.62 + }
1.63 +
1.64 + iMediaFatBits.Close();
1.65 + iScanFatBits.Close();
1.66 +
1.67 + }
1.68 +
1.69 +/**
1.70 + Creates the structure of this class.
1.71 + @param aMount The owning mount
1.72 +*/
1.73 +void CScanDrive::ConstructL(CFatMountCB* aMount)
1.74 + {
1.75 + ASSERT(aMount);
1.76 +
1.77 + //--- setting up
1.78 + iMount=aMount;
1.79 + iGenericError = ENoErrors;
1.80 + iDirError = ENoDirError;
1.81 + iMaxClusters = iMount->UsableClusters()+KFatFirstSearchCluster; //-- UsableClusters() doesn't count first 2 unused clusers
1.82 + //------------------------------
1.83 +
1.84 + //-- create bit vectors that will represent FAT on media and reconstructed by ScanDrive. Each bit in the vector represents 1 FAT cluster.
1.85 + const TUint32 KClustersNum = MaxClusters();
1.86 +
1.87 + CleanupClosePushL(iMediaFatBits);
1.88 + CleanupClosePushL(iScanFatBits);
1.89 +
1.90 + iMediaFatBits.CreateL(KClustersNum);
1.91 + iScanFatBits.CreateL(KClustersNum);
1.92 +
1.93 + CleanupStack::Pop(&iScanFatBits);
1.94 + CleanupStack::Pop(&iMediaFatBits);
1.95 + }
1.96 +
1.97 +//----------------------------------------------------------------------------------------------------
1.98 +/**
1.99 + FAT type-agnostic parser. Reads whole FAT and sets up a bit vector.
1.100 + for FAT12/16 it's OK, because the FAT12/16 is fully cached.
1.101 +*/
1.102 +void CScanDrive::DoParseFatL()
1.103 + {
1.104 + const TInt KMaxClusters = MaxClusters();
1.105 +
1.106 + iMediaFatBits.Fill(0);
1.107 +
1.108 + __PRINT1(_L("CScanDrive::DoParseFatL(), clusters:%d"), KMaxClusters);
1.109 +
1.110 + for(TInt i=KFatFirstSearchCluster; i<KMaxClusters; ++i)
1.111 + {
1.112 + const TUint32 nFatEntry = ReadFatL(i);
1.113 +
1.114 + //-- each '1' bit represents a used cluster
1.115 + if(nFatEntry != KSpareCluster)
1.116 + iMediaFatBits.SetBit(i);
1.117 + }
1.118 + }
1.119 +
1.120 +//----------------------------------------------------------------------------------------------------
1.121 +/**
1.122 + Parse FAT32 buffer.
1.123 + @param aBuf buffer, containing FAT32 entries (current portion of FAT)
1.124 + @param aCurrFatEntry current FAT entry processed
1.125 +*/
1.126 +void CScanDrive::DoParseFat32Buf(const TPtrC8& aBuf, TUint32& aCurrFatEntry)
1.127 + {
1.128 + ASSERT((aBuf.Size() & (sizeof(TFat32Entry)-1)) == 0);
1.129 +
1.130 + const TInt KNumEntries = aBuf.Size() >> KFat32EntrySzLog2;
1.131 + const TFat32Entry* const pFatEntry = (const TFat32Entry*)(aBuf.Ptr());
1.132 +
1.133 + for(TInt i=0; i<KNumEntries; ++i)
1.134 + {
1.135 + if(aCurrFatEntry >= KFatFirstSearchCluster)
1.136 + {
1.137 + if((pFatEntry[i] & KFat32EntryMask) != KSpareCluster)
1.138 + {//-- found a non-free FAT32 entry
1.139 + iMediaFatBits.SetBit(aCurrFatEntry);
1.140 + }
1.141 + }
1.142 + ++aCurrFatEntry;
1.143 + }
1.144 + }
1.145 +
1.146 +//----------------------------------------------------------------------------------------------------
1.147 +/**
1.148 + A specialised method to read and parse FAT32 using a larger buffer.
1.149 + 1. Larger buffer gives better read performance
1.150 + 2. using dedicated buffer doesn't trash FAT32 LRU cache.
1.151 +*/
1.152 +void CScanDrive::DoParseFat32L()
1.153 + {
1.154 + const TInt KNumClusters = MaxClusters();
1.155 +
1.156 + __PRINT1(_L("CScanDrive::DoParseFat32L(), clusters:%d"), KNumClusters);
1.157 +
1.158 + ASSERT(iMount->FatType() == EFat32);
1.159 +
1.160 + const TUint32 KFat1StartPos = iMount->StartOfFatInBytes();
1.161 + const TUint32 KFatSize = KNumClusters * sizeof(TFat32Entry); //-- usable size of one FAT.
1.162 +
1.163 + const TUint32 KFatBufSz = 32*K1KiloByte; //-- buffer size for FAT reading. 32K seems to be optimal size
1.164 +
1.165 + iMediaFatBits.Fill(0);
1.166 +
1.167 + RBuf8 buf;
1.168 + CleanupClosePushL(buf);
1.169 +
1.170 + //-- allocate memory for FAT parse buffer
1.171 + buf.CreateMaxL(KFatBufSz);
1.172 +
1.173 + //-- read FAT directly from the media into the large buffer and parse it
1.174 + TUint32 rem = KFatSize;
1.175 + TUint32 mediaPos = KFat1StartPos;
1.176 + TUint32 currFatEntry = 0;
1.177 +
1.178 + while(rem)
1.179 + {
1.180 + const TUint32 bytesToRead=Min(rem, KFatBufSz);
1.181 + TPtrC8 ptrData(buf.Ptr(), bytesToRead);
1.182 +
1.183 + //-- read portion of the FAT into buffer
1.184 + User::LeaveIfError(iMount->LocalDrive()->Read(mediaPos, bytesToRead, buf));
1.185 +
1.186 + //-- parse the buffer and populate bit vector
1.187 + DoParseFat32Buf(ptrData, currFatEntry);
1.188 +
1.189 + mediaPos += bytesToRead;
1.190 + rem -= bytesToRead;
1.191 + }
1.192 +
1.193 + buf.Close();
1.194 + CleanupStack::PopAndDestroy(&buf);
1.195 + }
1.196 +
1.197 +
1.198 +
1.199 +//----------------------------------------------------------------------------------------------------
1.200 +/**
1.201 + Sets up a bit list representation of the media fat
1.202 + Reads whole FAT and sets '1' bits in the bit vector corresponding to the occupied clusters.
1.203 +*/
1.204 +void CScanDrive::ReadMediaFatL()
1.205 + {
1.206 + ASSERT(iMount->ConsistentState());
1.207 +
1.208 + TInt nRes;
1.209 +
1.210 + if(iMount->FatType() == EFat32)
1.211 + {//-- for FAT32 try to use specialised method of parsing
1.212 + TRAP(nRes, DoParseFat32L())
1.213 + if(nRes == KErrNone)
1.214 + return;
1.215 + }
1.216 +
1.217 +
1.218 + //-- use old FAT-agnostic parsing
1.219 + DoParseFatL();
1.220 + }
1.221 +
1.222 +
1.223 +/**
1.224 + @return True if a directory error has been found
1.225 +*/
1.226 +TBool CScanDrive::IsDirError() const
1.227 + {
1.228 + return(iDirError!=0);
1.229 + }
1.230 +
1.231 +/**
1.232 + After StartL() and finishing allows us to know if there were any problems discovered at all.
1.233 + The client may wish to remount the filesystem if there were errors.
1.234 +
1.235 + @return The code describing the problem.
1.236 +*/
1.237 +CScanDrive::TGenericError CScanDrive::ProblemsDiscovered() const
1.238 +{
1.239 +
1.240 + if(IsDirError())
1.241 + return EScanDriveDirError;
1.242 + else
1.243 + return iGenericError;
1.244 +}
1.245 +
1.246 +/**
1.247 + Sets the flag indicating than there are errors in filesystem structure
1.248 + See ProblemsDiscovered()
1.249 +
1.250 + @param aError a code describing the error
1.251 +*/
1.252 +void CScanDrive::IndicateErrorsFound(TGenericError aError)
1.253 +{
1.254 + ASSERT(aError != ENoErrors);
1.255 + iGenericError = aError;
1.256 +}
1.257 +
1.258 +
1.259 +//----------------------------------------------------------------------------------------------------
1.260 +/**
1.261 + Start the scanner. The this calss description about what it actually does.
1.262 + @param aMode specifies the operational mode.
1.263 +*/
1.264 +void CScanDrive::StartL(TScanDriveMode aMode)
1.265 + {
1.266 + __PRINT2(_L("CScanDrive::StartL(%d), drive:%d"), aMode, iMount->DriveNumber());
1.267 + iScanDriveMode = aMode;
1.268 +
1.269 + //-- used for measuring time
1.270 + TTime timeStart;
1.271 + TTime timeEnd;
1.272 +
1.273 + timeStart.UniversalTime(); //-- take start time
1.274 +
1.275 + ReadMediaFatL();
1.276 +
1.277 + //timeEnd.UniversalTime(); //-- take end time
1.278 + //elapsedTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec);
1.279 + //__PRINT1(_L("#@@@ CScanDrive #1:%d ms "), elapsedTime);
1.280 +
1.281 + CheckDirStructureL();
1.282 +
1.283 + //-- uncomments a line below if you need to compare real and restored FAT tables and print out all differences
1.284 + //CompareFatsL(EFalse);
1.285 +
1.286 + //timeEnd.UniversalTime(); //-- take end time
1.287 + //elapsedTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec);
1.288 + //__PRINT1(_L("#@@@ CScanDrive #2:%d ms "), elapsedTime);
1.289 +
1.290 + if(CheckDiskMode())
1.291 + {//-- in check disk mode it is nesessarily just to detech FS errors
1.292 + CompareFatsL(ETrue); //-- will stop on the first error found
1.293 + }
1.294 + else
1.295 + {//-- In ScanDrive mode we need to find and fix Rugged FAT artefacts.
1.296 +
1.297 + if(IsDirError())
1.298 + FixupDirErrorL();
1.299 +
1.300 + CompareAndFixFatsL();
1.301 + }
1.302 +
1.303 + PrintErrors();
1.304 +
1.305 +
1.306 + timeEnd.UniversalTime(); //-- take end time
1.307 + const TInt elapsedTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec);
1.308 + (void)elapsedTime;
1.309 +
1.310 + __PRINT1(_L("CScanDrive: Directories visisted = %d\n"),iDirsChecked);
1.311 + __PRINT1(_L("#@@@ CScanDrive time taken:%d ms "), elapsedTime);
1.312 +
1.313 +
1.314 +
1.315 + return;
1.316 + }
1.317 +
1.318 +//----------------------------------------------------------------------------------------------------
1.319 +/**
1.320 + Fix errors detected by the drive scan
1.321 +
1.322 + @leave System wide error code
1.323 +*/
1.324 +void CScanDrive::FixupDirErrorL()
1.325 + {
1.326 + ASSERT(!CheckDiskMode());
1.327 +
1.328 + if(!IsDirError())
1.329 + return;
1.330 +
1.331 + if(iDirError==EScanMatchingEntry)
1.332 + {
1.333 + FindSameStartClusterL();
1.334 + FixMatchingEntryL();
1.335 + }
1.336 + else
1.337 + {
1.338 + FixPartEntryL();
1.339 + }
1.340 +
1.341 + IndicateErrorsFound(EScanDriveDirError); //-- indicate that we have found errors
1.342 + }
1.343 +
1.344 +//----------------------------------------------------------------------------------------------------
1.345 +/**
1.346 + Find positions of entries with same start cluster for error correction, searches
1.347 + the whole volume. Starts at the root directory.
1.348 +
1.349 + @leave System wide error code
1.350 +*/
1.351 +void CScanDrive::FindSameStartClusterL()
1.352 + {
1.353 + TInt err=FindStartClusterL(iMount->RootIndicator());
1.354 + if(err==KErrNone)
1.355 + return;
1.356 +
1.357 + for(TUint i=0;i<KMaxArrayDepth && iClusterListArray[i]!=NULL;++i)
1.358 + {
1.359 + RArray<TInt>* clusterList=iClusterListArray[i];
1.360 + for(TInt j=0;j<clusterList->Count();++j)
1.361 + {
1.362 + iRecursiveDepth=0;
1.363 + err=FindStartClusterL((*clusterList)[j]);
1.364 + if(err==KErrNone)
1.365 + return;
1.366 + }
1.367 + }
1.368 +
1.369 + __ASSERT_ALWAYS(err==KErrNone,User::Leave(KErrNotFound));
1.370 + }
1.371 +
1.372 +//----------------------------------------------------------------------------------------------------
1.373 +/**
1.374 + Scan through directory structure looking for start cluster found in iMatching
1.375 +
1.376 + @param aDirCluster Start cluster for scan to start
1.377 + @return System wide error value
1.378 + @leave
1.379 +*/
1.380 +TInt CScanDrive::FindStartClusterL(TInt aDirCluster)
1.381 + {
1.382 + __PRINT1(_L("CScanDrive::FindStartCluster dirCluster=%d"),aDirCluster);
1.383 + __ASSERT_ALWAYS(aDirCluster>=iMount->RootIndicator(),User::Leave(KErrCorrupt));
1.384 + if(++iRecursiveDepth==KMaxScanDepth)
1.385 + {
1.386 + --iRecursiveDepth;
1.387 + return(KErrNotFound);
1.388 + }
1.389 + TEntryPos entryPos(aDirCluster,0);
1.390 + TInt dirEntries=0;
1.391 + FOREVER
1.392 + {
1.393 + TFatDirEntry entry;
1.394 + ReadDirEntryL(entryPos,entry);
1.395 + if(entry.IsParentDirectory()||entry.IsCurrentDirectory()||entry.IsErased())
1.396 + {
1.397 + if(IsEndOfRootDir(entryPos))
1.398 + break;
1.399 + MoveToNextEntryL(entryPos);
1.400 + continue;
1.401 + }
1.402 + if(entry.IsEndOfDirectory())
1.403 + break;
1.404 + TBool isComplete;
1.405 + TEntryPos vfatPos=entryPos;
1.406 + isComplete=MoveToVFatEndL(entryPos,entry,dirEntries);
1.407 + __ASSERT_ALWAYS(isComplete,User::Leave(KErrBadName));
1.408 +
1.409 + TInt err=CheckEntryClusterL(entry,vfatPos);
1.410 + if(err==KErrNone)
1.411 + {
1.412 + --iRecursiveDepth;
1.413 + return(err);
1.414 + }
1.415 +
1.416 + if(IsEndOfRootDir(entryPos))
1.417 + break;
1.418 +
1.419 + MoveToNextEntryL(entryPos);
1.420 + }
1.421 + --iRecursiveDepth;
1.422 + return(KErrNotFound);
1.423 + }
1.424 +
1.425 +//----------------------------------------------------------------------------------------------------
1.426 +/**
1.427 + Procces aEntry to find matching start cluster
1.428 +
1.429 + @param aEntry Directory entry to check
1.430 + @param aEntryPos Position of directory to check
1.431 + @return System wide error value
1.432 + @leave
1.433 +*/
1.434 +TInt CScanDrive::CheckEntryClusterL(const TFatDirEntry& aEntry, const TEntryPos& aEntryPos)
1.435 + {
1.436 + __PRINT(_L("CScanDrive::CheckEntryClusterL"));
1.437 + if((TUint)iMount->StartCluster(aEntry)==iMatching.iStartCluster)
1.438 + {
1.439 + TBool complete=AddMatchingEntryL(aEntryPos);
1.440 + if(complete)
1.441 + return(KErrNone);
1.442 + }
1.443 + else if(aEntry.Attributes()&KEntryAttDir)
1.444 + return(FindStartClusterL(iMount->StartCluster(aEntry)));
1.445 +
1.446 + return(KErrNotFound);
1.447 + }
1.448 +
1.449 +//----------------------------------------------------------------------------------------------------
1.450 +/**
1.451 + Checks directory structure for errors, can be considered the start point of the scan.
1.452 + Handles recursion depth to avoid stack overflow.
1.453 +
1.454 + @leave System wide error code
1.455 +*/
1.456 +void CScanDrive::CheckDirStructureL()
1.457 + {
1.458 + CheckDirL(iMount->RootIndicator());
1.459 + // Due to recursive nature of CheckDirL when a depth of
1.460 + // KMaxScanDepth is reached clusters are stored in a list
1.461 + // and passed into CheckDirL afresh
1.462 +
1.463 + for(TUint i=0;i<KMaxArrayDepth && iClusterListArray[i]!=NULL;++i)
1.464 + {
1.465 + RArray<TInt>* clusterList=iClusterListArray[i];
1.466 + ++iListArrayIndex;
1.467 + for(TInt j=0;j<clusterList->Count();++j)
1.468 + {
1.469 + iRecursiveDepth=0;
1.470 + CheckDirL((*clusterList)[j]);
1.471 + }
1.472 + }
1.473 + }
1.474 +
1.475 +
1.476 +//----------------------------------------------------------------------------------------------------
1.477 +/**
1.478 + This function is called recursively with Process entry untill the whole volume has been scanned.
1.479 + Each directory entry is scanned for errors, these are recorded for later fixing.
1.480 +
1.481 + @param aCluster Directory cluster to start checking
1.482 + @leave System wide error codes
1.483 +*/
1.484 +void CScanDrive::CheckDirL(TUint32 aCluster)
1.485 + {
1.486 + __PRINT1(_L("CScanDrive::CheckDirL aCluster=%d"),aCluster);
1.487 +
1.488 + // check depth of recursion
1.489 + if(++iRecursiveDepth==KMaxScanDepth)
1.490 + {
1.491 + AddToClusterListL(aCluster);
1.492 + --iRecursiveDepth;
1.493 + return;
1.494 + }
1.495 +
1.496 + ++iDirsChecked;
1.497 +
1.498 + TEntryPos entryPos(aCluster,0);
1.499 + TInt dirEntries=0;
1.500 + FOREVER
1.501 + {
1.502 + TFatDirEntry entry;
1.503 + ReadDirEntryL(entryPos,entry);
1.504 + if(!iMount->IsEndOfClusterCh(entryPos.iCluster))
1.505 + ++dirEntries;
1.506 +
1.507 + if(entry.IsParentDirectory() || entry.IsCurrentDirectory() || entry.IsErased())
1.508 + {
1.509 + if(IsEndOfRootDir(entryPos))
1.510 + break;
1.511 +
1.512 + MoveToNextEntryL(entryPos);
1.513 + continue;
1.514 + }
1.515 +
1.516 + if(entry.IsEndOfDirectory())
1.517 + {
1.518 + if(aCluster)
1.519 + RecordClusterChainL(aCluster,dirEntries<<KSizeOfFatDirEntryLog2);
1.520 +
1.521 + break;
1.522 + }
1.523 +
1.524 + TEntryPos origPos=entryPos;
1.525 + TFatDirEntry origEntry=entry;
1.526 + TInt origDirEntries=dirEntries;
1.527 +
1.528 + const TBool isComplete = MoveToVFatEndL(entryPos,entry,dirEntries);
1.529 +
1.530 + if(!isComplete && CheckDiskMode())
1.531 + {//-- broken VFAT entryset; in CheckDisk mode this is the FS error, abort further activity
1.532 + IndicateErrorsFound(EInvalidEntrySize);
1.533 + User::Leave(KErrCorrupt);
1.534 + }
1.535 +
1.536 + // Only assume that this is a corrupted VFAT entry if the VFAT attributes are set;
1.537 + // assuming a non-VFAT corrupted entry is a VFAT entry is dangerous as we then assume that the
1.538 + // first byte is a count of entries to skip, thus completely invalidating the next <n> directories.
1.539 +
1.540 + //-- this code seems to deal with one of the Rugged FAT artefacts: partially deleted VFAT entryset, when DOS entry is deleted first
1.541 + //-- and delettion of VFAT ones had failed
1.542 + if(!isComplete && origEntry.IsVFatEntry())
1.543 + {
1.544 + AddPartialVFatL(origPos,origEntry);
1.545 + if(!IsEofF(entryPos.iCluster))
1.546 + {
1.547 + TInt toMove=origEntry.NumFollowing()-(dirEntries-origDirEntries);
1.548 + if(toMove)
1.549 + MovePastEntriesL(entryPos,entry,toMove,dirEntries);
1.550 + }
1.551 + else
1.552 + {
1.553 + // we fell off the end of the directory file, so just strip this
1.554 + // incomplete long file name entry
1.555 + dirEntries = origDirEntries;
1.556 + }
1.557 + }
1.558 + else
1.559 + {
1.560 + ProcessEntryL(entry);
1.561 + }
1.562 +
1.563 + if(IsEndOfRootDir(entryPos))
1.564 + break;
1.565 +
1.566 + MoveToNextEntryL(entryPos);
1.567 + }
1.568 + --iRecursiveDepth;
1.569 + }
1.570 +
1.571 +//----------------------------------------------------------------------------------------------------
1.572 +/**
1.573 + Process non trivial entries, such as files, if they are correct by filling out their
1.574 + cluster allocation in the bit packed Fat table. If it comes accross a directory
1.575 + CheckDirL will be called.
1.576 +
1.577 + @param aEntry Directory entry to check
1.578 + @leave System wide error code
1.579 +*/
1.580 +void CScanDrive::ProcessEntryL(const TFatDirEntry& aEntry)
1.581 + {
1.582 + __PRINT(_L("CScanDrive::ProcessEntryL"));
1.583 + TInt entryAtt=aEntry.Attributes();
1.584 +
1.585 + __ASSERT_ALWAYS(!(entryAtt&~KEntryAttMaskSupported)&&!aEntry.IsErased(),User::Leave(KErrCorrupt));
1.586 +
1.587 + if(!(entryAtt&(KEntryAttDir|KEntryAttVolume)) && iMount->StartCluster(aEntry)>0)
1.588 + {//-- this is a file with length >0. Check that its cluster chain corresponds to its size
1.589 + RecordClusterChainL(iMount->StartCluster(aEntry),(TUint) aEntry.Size());
1.590 + }
1.591 + else if(entryAtt&KEntryAttDir)
1.592 + {//-- this is the directory, walk into it
1.593 + CheckDirL(iMount->StartCluster(aEntry));
1.594 + }
1.595 + }
1.596 +
1.597 +//----------------------------------------------------------------------------------------------------
1.598 +/**
1.599 + Walks the cluster chain for a correct file or directory, checks that the cluster
1.600 + has not already been used and that the correct number of clusters are allocated for the
1.601 + size of file. Registers cluster as used, if correct.
1.602 +
1.603 + @param aCluster Cluster chain start point
1.604 + @param aSizeInBytes Size of the file or directory in bytes
1.605 + @leave System wide error values
1.606 +*/
1.607 +void CScanDrive::RecordClusterChainL(TInt aCluster, TUint aSizeInBytes)
1.608 + {
1.609 + __PRINT2(_L("CScanDrive::RecordClusterChainL() cl:%d, sz:%d") ,aCluster, aSizeInBytes);
1.610 + __ASSERT_ALWAYS(aCluster>0, User::Leave(KErrCorrupt));
1.611 +
1.612 + TUint clusterCount;
1.613 +
1.614 + if(aSizeInBytes==0)
1.615 + clusterCount=1;
1.616 + else
1.617 + {
1.618 + const TUint64 tmp = aSizeInBytes + Pow2_64(iMount->ClusterSizeLog2()) - 1;
1.619 + clusterCount = (TUint) (tmp >> iMount->ClusterSizeLog2());
1.620 + }
1.621 +
1.622 + TInt startCluster=aCluster;
1.623 + while(clusterCount)
1.624 + {
1.625 + if(IsClusterUsedL(aCluster))
1.626 + {//-- this cluster already seems to belong to some other object; crosslinked cluster chain. Can't fix it.
1.627 + if(CheckDiskMode())
1.628 + {//-- in check disk mode this is a FS error; Indicate error and abort furter scanning
1.629 + __PRINT1(_L("CScanDrive::RecordClusterChainL #1 %d"),aCluster);
1.630 + IndicateErrorsFound(EClusterAlreadyInUse);
1.631 + User::Leave(KErrCorrupt);
1.632 + }
1.633 +
1.634 + __ASSERT_ALWAYS(!IsDirError() && iMatching.iStartCluster==0 && aCluster==startCluster,User::Leave(KErrCorrupt));
1.635 + iMatching.iStartCluster=aCluster;
1.636 + iDirError=EScanMatchingEntry; //ERROR POINT
1.637 + IndicateErrorsFound(EScanDriveDirError); //-- indicate that we have found errors
1.638 + return;
1.639 + }
1.640 +
1.641 +
1.642 + if(clusterCount==1)
1.643 + {
1.644 + if(!iMount->IsEndOfClusterCh(ReadFatL(aCluster)))
1.645 + {//-- seems to be a rugged FAT artefact; File truncation had failed before and now file length is less than
1.646 + //-- the corresponding cluster chain shall be. It will be truncated.
1.647 + iTruncationCluster = aCluster;
1.648 +
1.649 + if(CheckDiskMode())
1.650 + {//-- in check disk mode this is a FS error; Indicate error and abort furter scanning
1.651 + __PRINT1(_L("CScanDrive::RecordClusterChainL #2 %d"),aCluster);
1.652 + IndicateErrorsFound(EInvalidEntrySize);
1.653 + User::Leave(KErrCorrupt);
1.654 + }
1.655 + }
1.656 +
1.657 + //__PRINT1(_L("#--: %d -> EOC"), aCluster);
1.658 + MarkClusterUsedL(aCluster);
1.659 + return;
1.660 + }
1.661 + else
1.662 + {
1.663 + const TUint clusterVal=ReadFatL(aCluster);
1.664 +
1.665 + //__PRINT2(_L("#--: %d -> %d"), aCluster, clusterVal);
1.666 +
1.667 + __ASSERT_ALWAYS(!IsEofF(clusterVal) && clusterVal !=KSpareCluster, User::Leave(KErrCorrupt));
1.668 + MarkClusterUsedL(aCluster);
1.669 + aCluster=clusterVal;
1.670 + --clusterCount;
1.671 + }
1.672 +
1.673 + }//while(clusterCount)
1.674 + }
1.675 +
1.676 +//----------------------------------------------------------------------------------------------------
1.677 +/**
1.678 + Move to dos entry, checking all vfat entry ID numbers are in sequence.
1.679 + Assumes aEntry is not erased
1.680 +
1.681 + @param aPos Position of the entry to move from, returns with new position
1.682 + @param aEntry The Dos entry after the Vfat entries on return
1.683 + @param aDirLength Running total of the length of the directory in entries
1.684 + @leave System wide error codes
1.685 + @return EFalse if not valid vfat entries or dos entry, else returns ETrue
1.686 +*/
1.687 +TBool CScanDrive::MoveToVFatEndL(TEntryPos& aPos,TFatDirEntry& aEntry,TInt& aDirLength)
1.688 + {
1.689 + __PRINT2(_L("CScanDrive::MoveToVFatEndL cluster=%d,pos=%d"),aPos.iCluster,aPos.iPos);
1.690 + if(!aEntry.IsVFatEntry())
1.691 + return IsDosEntry(aEntry);
1.692 +
1.693 + TInt toFollow=aEntry.NumFollowing();
1.694 + __ASSERT_ALWAYS(toFollow>0 && !aEntry.IsErased(), User::Leave(KErrCorrupt));
1.695 +
1.696 + FOREVER
1.697 + {
1.698 + MoveToNextEntryL(aPos);
1.699 + ReadDirEntryL(aPos,aEntry);
1.700 + ++aDirLength;
1.701 + --toFollow;
1.702 + if(!toFollow)
1.703 + break;
1.704 +
1.705 + if(!IsValidVFatEntry(aEntry,toFollow))
1.706 + return(EFalse);
1.707 + }
1.708 +
1.709 + return(IsDosEntry(aEntry));
1.710 + }
1.711 +
1.712 +//----------------------------------------------------------------------------------------------------
1.713 +/**
1.714 + Check if an entry is valid VFat
1.715 +
1.716 + @param aEntry Entry to check
1.717 + @param aPrevNum Number into VFat entries for a dos entry to ensure in correct position
1.718 + @return ETrue if aEntry is a valid vfat entry
1.719 +*/
1.720 +TBool CScanDrive::IsValidVFatEntry(const TFatDirEntry& aEntry,TInt aPrevNum)const
1.721 + {
1.722 + if(aEntry.IsErased()||!aEntry.IsVFatEntry())
1.723 + return EFalse;
1.724 +
1.725 + return(aEntry.NumFollowing()==aPrevNum);
1.726 + }
1.727 +
1.728 +//----------------------------------------------------------------------------------------------------
1.729 +/**
1.730 + Check if an entry is a Dos entry
1.731 +
1.732 + @param aEntry Entry to check
1.733 + @return ETrue if aEntry is a dos entry
1.734 +*/
1.735 +TBool CScanDrive::IsDosEntry(const TFatDirEntry& aEntry)const
1.736 + {
1.737 + TBool res = !(aEntry.Attributes()&~KEntryAttMaskSupported) && !aEntry.IsErased() && !aEntry.IsVFatEntry() && !aEntry.IsEndOfDirectory();
1.738 + return res;
1.739 + }
1.740 +
1.741 +//----------------------------------------------------------------------------------------------------
1.742 +/**
1.743 + Add partial entry to iPartEntry under the error condition of not all Vfat entries being present
1.744 +
1.745 + @param aStartPos Position of the Dos entry associated with the VFat entries
1.746 + @param aEntry Directory Entry of the Dos entry associated with the VFat entries
1.747 + @leave KErrCorrupt Occurs if the entry is not valid
1.748 +*/
1.749 +void CScanDrive::AddPartialVFatL(const TEntryPos& aStartPos, const TFatDirEntry& aEntry)
1.750 + {
1.751 + __PRINT2(_L("CScanDrive::AddPartialVFatL cluster=%d pos=%d"),aStartPos.iCluster,aStartPos.iPos);
1.752 + __ASSERT_ALWAYS(!IsDirError(),User::Leave(KErrCorrupt));
1.753 + iPartEntry.iEntryPos=aStartPos;
1.754 + iPartEntry.iEntry=aEntry;
1.755 + iDirError=EScanPartEntry;
1.756 + }
1.757 +
1.758 +//----------------------------------------------------------------------------------------------------
1.759 +/**
1.760 + Add entry position to iMatching
1.761 +
1.762 + @param aEntryPos Position of the entry with the matching entry
1.763 + @leave KErrCorrupt if the start cluster is 0 or more that two matching entries occurs
1.764 + @return
1.765 +*/
1.766 +TBool CScanDrive::AddMatchingEntryL(const TEntryPos& aEntryPos)
1.767 + {
1.768 + __PRINT2(_L("CScanDrive::AddMatchingEntryL cluster=%d pos=%d"),aEntryPos.iCluster,aEntryPos.iPos);
1.769 + __ASSERT_ALWAYS(iMatching.iStartCluster>0 && iMatching.iCount<KMaxMatchingEntries,User::Leave(KErrCorrupt));
1.770 + iMatching.iEntries[iMatching.iCount++]=aEntryPos;
1.771 + return iMatching.iCount==KMaxMatchingEntries;
1.772 + }
1.773 +
1.774 +
1.775 +//----------------------------------------------------------------------------------------------------
1.776 +/**
1.777 + Scan for differnces in the new and old FAT table writing them to media if discovered
1.778 + It is supposed to be called in 'ScanDrive' mode only
1.779 +
1.780 + @leave System wide error codes
1.781 +*/
1.782 +void CScanDrive::CompareAndFixFatsL()
1.783 + {
1.784 + __PRINT1(_L("CScanDrive::CompareAndFixFatsL() drv:%d"),iMount->DriveNumber());
1.785 +
1.786 + ASSERT(!CheckDiskMode());
1.787 +
1.788 + TUint32 nClustersFixed = 0; //-- fixed clusters count
1.789 + TUint32 nBadClusters = 0; //-- bad cluster count
1.790 + TUint32 dirtyFatSector = 0; //-- FAT table media sector with not-flushed data
1.791 +
1.792 + const TUint32 KSectorSzLog2 = iMount->SectorSizeLog2(); //-- Log2(media Sector Size)
1.793 +
1.794 + TUint32 diffPos;
1.795 + if(iMediaFatBits.Diff(iScanFatBits, diffPos))
1.796 + {//-- there is a difference between FATs' bit representation
1.797 +
1.798 + ASSERT(diffPos >= KFatFirstSearchCluster);
1.799 +
1.800 + const TUint32 maxClusters = iScanFatBits.Size();
1.801 +
1.802 + for(TUint32 i=diffPos; i<maxClusters; ++i)
1.803 + {
1.804 + if(BoolXOR(iMediaFatBits[i], iScanFatBits[i]))
1.805 + {//-- difference in the cluster "i" between a real FAT and what ScanDrive restored.
1.806 +
1.807 + //-- indicate that there are some problems in FAT. and we probably wrote something there.
1.808 + IndicateErrorsFound(EScanDriveDirError);
1.809 +
1.810 + //-- skip BAD cluster, can't mark it as unused.
1.811 + if(iMount->IsBadCluster(ReadFatL(i)))
1.812 + {
1.813 + ++nBadClusters;
1.814 + continue;
1.815 + }
1.816 +
1.817 + //-- here we found a lost cluster. Its FAT entry will be replaced with KSpareCluster. In the case of multiple lost clusters FAT table will
1.818 + //-- be flushed on media sector basis. It is much faster than flushing FAT after every write and will
1.819 + //-- guarantee that FAT won't be corrupted if the media driver provides atomic sector write.
1.820 + if(nClustersFixed == 0)
1.821 + {//-- this is the first lost cluster entry we found
1.822 +
1.823 + //-- relative FAT media sector for the 'i' entry. The real value doesn't matter,
1.824 + //-- we will just be flushing FAT before writing to the different FAT media sector.
1.825 + dirtyFatSector = iMount->FAT().PosInBytes(i) >> KSectorSzLog2;
1.826 +
1.827 + iMount->FAT().WriteL(i, KSpareCluster); //-- fix lost cluster
1.828 + }
1.829 + else
1.830 + {
1.831 + const TUint32 fatSec = iMount->FAT().PosInBytes(i) >> KSectorSzLog2;
1.832 +
1.833 + if(fatSec != dirtyFatSector)
1.834 + {//-- we are going to write to a differrent media sector
1.835 + iMount->FAT().FlushL();
1.836 + iMount->FAT().WriteL(i, KSpareCluster); //-- fix lost cluster
1.837 + dirtyFatSector = fatSec;
1.838 + }
1.839 + else
1.840 + {//-- write to the same FAT media sector without flushing
1.841 + iMount->FAT().WriteL(i, KSpareCluster); //-- fix lost cluster
1.842 + }
1.843 +
1.844 + }
1.845 +
1.846 + ++nClustersFixed;
1.847 +
1.848 + }//if(BoolXOR(iMediaFatBits[i], iScanFatBits[i])
1.849 +
1.850 + }//for(TInt i=KFatFirstSearchCluster; i<maxClusters; ++i)
1.851 +
1.852 + }//if(iMediaFatBits.Diff(iScanFatBits, diffPos))
1.853 +
1.854 +
1.855 + if(nClustersFixed)
1.856 + iMount->FAT().FlushL();
1.857 +
1.858 + //------
1.859 +
1.860 + if(iTruncationCluster != 0)
1.861 + {
1.862 + iMount->FAT().WriteFatEntryEofL(iTruncationCluster);
1.863 + iMount->FAT().FlushL();
1.864 +
1.865 + //-- indicate that there are some problems in FAT. and we probably wrote something there.
1.866 + IndicateErrorsFound(EScanDriveDirError); //-- indicate that we have found errors
1.867 +
1.868 + ++nClustersFixed;
1.869 + }
1.870 +
1.871 + __PRINT2(_L("CScanDrive::WriteNewFatsL() fixed:%d, bad:%d"), nClustersFixed, nBadClusters);
1.872 + }
1.873 +
1.874 +//----------------------------------------------------------------------------------------------------
1.875 +/**
1.876 + Read the "Rugged FAT" ID, stored in reserved2 in the Dos entry or associated with the Dos entry of the
1.877 + Entry at the position passed in. This is used to find which version of two matching entries should be kept.
1.878 +
1.879 +
1.880 + @param aVFatPos Position of an entry to read ID from
1.881 + @leave System wide error codes
1.882 + @return The ID found in reserved2 field of dos entry
1.883 +*/
1.884 +TInt CScanDrive::GetReservedidL(TEntryPos aVFatPos)
1.885 + {
1.886 + __PRINT(_L("CScanDrive::GetReservedidL"));
1.887 + TFatDirEntry entry;
1.888 + ReadDirEntryL(aVFatPos,entry);
1.889 + if(!IsDosEntry(entry))
1.890 + {
1.891 + TInt toMove=entry.NumFollowing();
1.892 + while(toMove--)
1.893 + MoveToNextEntryL(aVFatPos);
1.894 + ReadDirEntryL(aVFatPos,entry);
1.895 + }
1.896 + return(entry.RuggedFatEntryId());
1.897 + }
1.898 +
1.899 +//----------------------------------------------------------------------------------------------------
1.900 +/**
1.901 + Erase part entry found in iPartEntry
1.902 + @leave System wide error code
1.903 +*/
1.904 +void CScanDrive::FixPartEntryL()
1.905 + {
1.906 + __PRINT2(_L("CScanDrive::FixPartEntryL cluster=%d,pos=%d"),iPartEntry.iEntryPos.iCluster,iPartEntry.iEntryPos.iPos);
1.907 + ASSERT(!CheckDiskMode());
1.908 + iMount->EraseDirEntryL(iPartEntry.iEntryPos,iPartEntry.iEntry);
1.909 + IndicateErrorsFound(EScanDriveDirError); //-- indicate that we have found errors
1.910 + }
1.911 +
1.912 +//----------------------------------------------------------------------------------------------------
1.913 +/**
1.914 + Delete entry with largest value in the reserved2 section(bytes 20 and 21) of dos entry
1.915 +
1.916 + @leave System wide error code
1.917 +*/
1.918 +void CScanDrive::FixMatchingEntryL()
1.919 + {
1.920 +
1.921 + __PRINT1(_L("CScanDrive::FixMatchingEntryL() start cluster=%d"),iMatching.iStartCluster);
1.922 + __ASSERT_ALWAYS(iMatching.iCount==KMaxMatchingEntries,User::Leave(KErrCorrupt));
1.923 + ASSERT(!CheckDiskMode());
1.924 +
1.925 + TInt idOne=GetReservedidL(iMatching.iEntries[0]);
1.926 + TInt idTwo=GetReservedidL(iMatching.iEntries[1]);
1.927 + TFatDirEntry entry;
1.928 + TInt num=idOne>idTwo?0:1;
1.929 + ReadDirEntryL(iMatching.iEntries[num],entry);
1.930 + iMount->EraseDirEntryL(iMatching.iEntries[num],entry);
1.931 + IndicateErrorsFound(EScanDriveDirError); //-- indicate that we have found errors
1.932 + }
1.933 +
1.934 +//----------------------------------------------------------------------------------------------------
1.935 +/**
1.936 + Move past specified number of entries
1.937 +
1.938 + @param aEntryPos Start position to move from, updated as move takes place
1.939 + @param aEntry Directory entry moved to
1.940 + @param aToMove Number of entries to move through
1.941 + @param aDirEntries Number of entries moved, updated as move takes place
1.942 + @leave System wide error code
1.943 +*/
1.944 +void CScanDrive::MovePastEntriesL(TEntryPos& aEntryPos,TFatDirEntry& aEntry,TInt aToMove,TInt& aDirEntries)
1.945 + {
1.946 + while(aToMove-- && !IsEofF(aEntryPos.iCluster))
1.947 + {
1.948 + MoveToNextEntryL(aEntryPos);
1.949 + ++aDirEntries;
1.950 + }
1.951 + ReadDirEntryL(aEntryPos,aEntry);
1.952 + }
1.953 +
1.954 +//----------------------------------------------------------------------------------------------------
1.955 +/**
1.956 + Adds aCluster to cluster list array so that it may be revisited later, avoids stack
1.957 + over flow
1.958 +
1.959 + @param aCluster Directory cluster number to add to the list
1.960 + @leave KErrNoMemory If allocation fails
1.961 +*/
1.962 +void CScanDrive::AddToClusterListL(TInt aCluster)
1.963 + {
1.964 +
1.965 + if(iListArrayIndex>=KMaxArrayDepth)
1.966 + return;
1.967 +
1.968 + if(iClusterListArray[iListArrayIndex]==NULL)
1.969 + iClusterListArray[iListArrayIndex]=new(ELeave) RArray<TInt>(KClusterListGranularity);
1.970 + iClusterListArray[iListArrayIndex]->Append(aCluster);
1.971 + }
1.972 +
1.973 +
1.974 +//----------------------------------------------------------------------------------------------------
1.975 +/**
1.976 + Used in "CheckDisk" mode mostly. Compares first FAT table on the media with the FAT bitmap restored by walking the directory structure.
1.977 + Displays any differences and records an error if found.
1.978 +
1.979 + @param aStopOnFirstErrorFound if ETrue will stop after discovering first error (FATs discrepancy)
1.980 +
1.981 + @leave System wide error codes
1.982 +*/
1.983 +void CScanDrive::CompareFatsL(TBool aStopOnFirstErrorFound)
1.984 + {
1.985 + __PRINT1(_L("CScanDrive::CompareFatsL(%d)"), aStopOnFirstErrorFound);
1.986 +
1.987 +
1.988 + TUint32 diffPos;
1.989 + if(!iMediaFatBits.Diff(iScanFatBits, diffPos))
1.990 + return; //-- FATs are identical
1.991 +
1.992 + //-- there is a difference between the real FAT and reconstructed one. Find the mismaching bit and fix FAT.
1.993 + const TUint clusters = iMount->UsableClusters();
1.994 + ASSERT(diffPos < (TUint32)clusters);
1.995 +
1.996 + TUint scanusedcnt=0;
1.997 + TUint mediausedcnt=0;
1.998 +
1.999 + for(TUint i=diffPos; i<clusters; ++i)
1.1000 + {
1.1001 + const TBool bRealFatEntry = iMediaFatBits[i];
1.1002 + const TBool bNewFatEntry = iScanFatBits[i];
1.1003 +
1.1004 + if(BoolXOR(bRealFatEntry, bNewFatEntry))
1.1005 + {//-- mismatch between FAT on the media and the FAT bitmap restored by walking directory structure
1.1006 +
1.1007 + if(bRealFatEntry)
1.1008 + {//-- FAT[i] on the media is marked as occupied, but retored FAT bitmap shows that it is free
1.1009 + if(iMount->IsBadCluster(ReadFatL(i)))
1.1010 + continue; //-- this is a BAD cluster it can't be occupied by the FS object, OK.
1.1011 +
1.1012 + __PRINT2(_L("FAT[%d] = %d\n"), i, ReadFatL(i));
1.1013 + __PRINT1(_L("iTruncationCluster = %d\n"), iTruncationCluster);
1.1014 +
1.1015 + //-- this is a lost cluster
1.1016 + if(!IsEofF(ReadFatL(i)) && (i==iTruncationCluster))
1.1017 + {//-- seems to be a Rugged FAT ertefact
1.1018 + __PRINT1(_L("Hanging cluster = %d\n"),i);
1.1019 + }
1.1020 + else
1.1021 + {
1.1022 + __PRINT1(_L("Lost cluster=%d\n"),i);
1.1023 + }
1.1024 +
1.1025 +
1.1026 + IndicateErrorsFound(EBadClusterValue);
1.1027 + }
1.1028 + else
1.1029 + {//-- FAT[i] on the media is marked as free, but retored FAT bitmap shows that it is occupied by some object
1.1030 + IndicateErrorsFound(EClusterAlreadyInUse);
1.1031 + __PRINT1(_L("Unflushed cluster = %d\n"),i);
1.1032 + }
1.1033 +
1.1034 + if(aStopOnFirstErrorFound)
1.1035 + break; //-- not asked to check for errors further
1.1036 +
1.1037 + }
1.1038 +
1.1039 + if(bRealFatEntry)
1.1040 + mediausedcnt++;
1.1041 +
1.1042 + if(bNewFatEntry)
1.1043 + scanusedcnt++;
1.1044 + }
1.1045 +
1.1046 + __PRINT2(_L("Scan Fat Used=%d, Media Fat Used=%d \n"),scanusedcnt,mediausedcnt);
1.1047 + }
1.1048 +
1.1049 +//----------------------------------------------------------------------------------------------------
1.1050 +/**
1.1051 + For debug purposes, print errors found as debug output
1.1052 +*/
1.1053 +void CScanDrive::PrintErrors()
1.1054 + {
1.1055 +#if defined(_DEBUG)
1.1056 + __PRINT1(_L("Directories visisted = %d\n"),iDirsChecked);
1.1057 +
1.1058 + if(iDirError==EScanPartEntry)
1.1059 + {
1.1060 + __PRINT2(_L("Part entry-dir cluster=%d,dir pos=%d,\n"),iPartEntry.iEntryPos.iCluster,iPartEntry.iEntryPos.iPos);
1.1061 + }
1.1062 + else if(iDirError==EScanMatchingEntry)
1.1063 + {
1.1064 + __PRINT1(_L("Matching cluster - cluster no=%d\n"),iMatching.iStartCluster);
1.1065 + __PRINT2(_L("\tcluster 1 - dir cluster=%d,dir pos=%d\n"),iMatching.iEntries[0].iCluster,iMatching.iEntries[0].iPos);
1.1066 + __PRINT2(_L("\tcluster 2 - dir cluster=%d,dir pos=%d\n"),iMatching.iEntries[1].iCluster,iMatching.iEntries[1].iPos);
1.1067 + }
1.1068 +#endif
1.1069 + }
1.1070 +
1.1071 +
1.1072 +
1.1073 +/**
1.1074 +Read a FAT directory entry from disk, either reads directly from the main cache or
1.1075 +from the cluster buffer if scan drive is running in a seperate thread.
1.1076 +
1.1077 +@param aPos Media position of entry to read
1.1078 +@param aDirEntry Contents of directory entry read
1.1079 +@leave System wide error code
1.1080 +*/
1.1081 +void CScanDrive::ReadDirEntryL(const TEntryPos& aPos,TFatDirEntry& aDirEntry)
1.1082 + {
1.1083 + //__PRINT(_L("CScanDrive::ReadDirEntryL"));
1.1084 + if (iMount->IsEndOfClusterCh(aPos.iCluster))
1.1085 + {
1.1086 + Mem::FillZ(&aDirEntry,sizeof(TFatDirEntry));
1.1087 + return;
1.1088 + }
1.1089 +
1.1090 + iMount->ReadDirEntryL(aPos, aDirEntry);
1.1091 + }
1.1092 +
1.1093 +
1.1094 +/**
1.1095 + Move to next directory entry, if anEntry is at the end of the cluster, and we are not
1.1096 + the root dir, move it to the next cluster in the chain.
1.1097 +
1.1098 + @param aPos Current directory position up dated to position of next entry.
1.1099 +*/
1.1100 +void CScanDrive::MoveToNextEntryL(TEntryPos& aPos)
1.1101 + {
1.1102 + //__PRINT(_L("CScanDrive::MoveToNextEntryL"));
1.1103 + iMount->MoveToNextEntryL(aPos);
1.1104 + }
1.1105 +
1.1106 +/**
1.1107 + Read a cluster from the Media Fat if scan run in a seperate thread read from scan fat table
1.1108 + otherwise read from mount owned Fat table
1.1109 +
1.1110 + @param aClusterNum Cluster to read
1.1111 + @return Value of cluster read from Fat
1.1112 +*/
1.1113 +TUint32 CScanDrive::ReadFatL(TUint aClusterNum)
1.1114 + {
1.1115 + if(aClusterNum < KFatFirstSearchCluster || aClusterNum >= MaxClusters())
1.1116 + {
1.1117 + IndicateErrorsFound(EBadClusterNumber);
1.1118 + User::Leave(KErrCorrupt);
1.1119 + }
1.1120 +
1.1121 + //-- actually, ReadL() can leave with some error code, that won't be reflected in IndicateErrorsFound().
1.1122 + //-- it's possible to improve but is it worth it?
1.1123 + return iMount->FAT().ReadL(aClusterNum);
1.1124 + }
1.1125 +
1.1126 +
1.1127 +/**
1.1128 + Set a cluster as visited in the bit packed scan Fat
1.1129 + @param aCluster Cluster number
1.1130 +*/
1.1131 +void CScanDrive::MarkClusterUsedL(TUint aClusterNum)
1.1132 + {
1.1133 + if(aClusterNum < KFatFirstSearchCluster || aClusterNum >= MaxClusters())
1.1134 + {
1.1135 + IndicateErrorsFound(EBadClusterNumber);
1.1136 + User::Leave(KErrCorrupt);
1.1137 + }
1.1138 +
1.1139 + iScanFatBits.SetBit(aClusterNum);
1.1140 + }
1.1141 +
1.1142 +
1.1143 +/**
1.1144 + Query whether a cluster is already set as used
1.1145 + @param aCluster Cluster to query
1.1146 +*/
1.1147 +TBool CScanDrive::IsClusterUsedL(TUint aClusterNum)
1.1148 + {
1.1149 + if(aClusterNum < KFatFirstSearchCluster || aClusterNum >= MaxClusters())
1.1150 + {
1.1151 + IndicateErrorsFound(EBadClusterNumber);
1.1152 + User::Leave(KErrCorrupt);
1.1153 + }
1.1154 +
1.1155 + return iScanFatBits[aClusterNum];
1.1156 + }
1.1157 +
1.1158 +/**
1.1159 + @param aPos Position in a directory cluster
1.1160 + @return ETrue if aPos is the last entry in the root directory
1.1161 +*/
1.1162 +TBool CScanDrive::IsEndOfRootDir(const TEntryPos& aPos)const
1.1163 + {
1.1164 + return(iMount->IsRootDir(aPos)&&(iMount->StartOfRootDirInBytes()+aPos.iPos==(iMount->RootDirEnd()-KSizeOfFatDirEntry)));
1.1165 + }
1.1166 +
1.1167 +/**
1.1168 + @param aVal Value of the cluster to be tested
1.1169 + @return ETrue if aVal is the end of cluster marker
1.1170 +*/
1.1171 +TBool CScanDrive::IsEofF(TInt aVal) const
1.1172 + {
1.1173 + return iMount->IsEndOfClusterCh(aVal);
1.1174 + }
1.1175 +
1.1176 +/** @return max. number of clusters on the volume being scanned */
1.1177 +TUint32 CScanDrive::MaxClusters() const
1.1178 + {
1.1179 + ASSERT(iMaxClusters);
1.1180 + return iMaxClusters;
1.1181 + }
1.1182 +
1.1183 +/** @return ETrue in we are operating in "CheckDisk" mode*/
1.1184 +TBool CScanDrive::CheckDiskMode() const
1.1185 + {
1.1186 + return iScanDriveMode == ECheckDisk;
1.1187 + }
1.1188 +
1.1189 +
1.1190 +
1.1191 +
1.1192 +
1.1193 +
1.1194 +
1.1195 +
1.1196 +