1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/userlibandfileserver/fileserver/sfat/sl_scan.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,696 @@
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\sfat\sl_scan.cpp
1.18 +// ScanDrive code, specific for EFAT.FSY
1.19 +//
1.20 +//
1.21 +
1.22 +/**
1.23 + @file
1.24 + @internalTechnology
1.25 +*/
1.26 +
1.27 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1.28 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1.29 +//!!
1.30 +//!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it
1.31 +//!!
1.32 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1.33 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1.34 +
1.35 +
1.36 +//#define DEBUG_SCANDRIVE
1.37 +
1.38 +#include "sl_std.h"
1.39 +#include "sl_scandrv.h"
1.40 +
1.41 +const TInt KEndOfDirectory = 0xFFFF; ///< End of directory marker
1.42 +const TInt KMaxScanDepth = 20; ///< Maximum scan depth of to avoid stack over flow
1.43 +const TInt KClusterListGranularity = 8; ///< Granularity of cluster list used for storage of clusters when KMaxScanDepth is reached
1.44 +
1.45 +/**
1.46 +Creates a CScanDrive
1.47 +
1.48 +@param aMount The owning mount
1.49 +*/
1.50 +CScanDrive* CScanDrive::NewL(CFatMountCB* aMount)
1.51 + {
1.52 + if(aMount==NULL)
1.53 + User::Leave(KErrArgument);
1.54 + CScanDrive* self=new (ELeave) CScanDrive();
1.55 + CleanupStack::PushL(self);
1.56 + self->ConstructL(aMount);
1.57 + CleanupStack::Pop();
1.58 + return self;
1.59 + }
1.60 +
1.61 +
1.62 +CScanDrive::CScanDrive()
1.63 +//
1.64 +// Constructor
1.65 +//
1.66 + {
1.67 + }
1.68 +
1.69 +
1.70 +CScanDrive::~CScanDrive()
1.71 +//
1.72 +// Destructor
1.73 +//
1.74 + {
1.75 + delete iNewFat;
1.76 + for(TInt i=0;i<KMaxArrayDepth && iClusterListArray[i]!=NULL;++i)
1.77 + {
1.78 + iClusterListArray[i]->Close();
1.79 + delete iClusterListArray[i];
1.80 + }
1.81 + }
1.82 +
1.83 +
1.84 +void CScanDrive::ConstructL(CFatMountCB* aMount)
1.85 +//
1.86 +// Create the new fat and initalise
1.87 +//
1.88 + {
1.89 + iMount=aMount;
1.90 + iNewFat=CCheckFatTable::NewL(aMount);
1.91 + iNewFat->InitializeL();
1.92 + }
1.93 +
1.94 +
1.95 +TBool CScanDrive::AlreadyExistsL(TInt aCluster)const
1.96 +//
1.97 +// Return ETrue if aCluster in the new fat contains a non-zero entry
1.98 +//
1.99 + {
1.100 + return(iNewFat->ReadL(aCluster)!=0);
1.101 + }
1.102 +
1.103 +
1.104 +TBool CScanDrive::IsEndOfRootDir(const TEntryPos& aPos)const
1.105 +//
1.106 +// Return ETrue if aPos is the last entry in the root directory
1.107 +//
1.108 + {
1.109 + return(iMount->IsRootDir(aPos)&&(iMount->StartOfRootDirInBytes()+aPos.iPos==(iMount->RootDirEnd()-KSizeOfFatDirEntry)));
1.110 + }
1.111 +
1.112 +/**
1.113 +@param aVal Value of the cluster to be tested
1.114 +@return ETrue if aVal is the end of cluster marker
1.115 +*/
1.116 +TBool CScanDrive::IsEofF(TInt aVal)const
1.117 + {
1.118 + return iMount->IsEndOfClusterCh(aVal);
1.119 + }
1.120 +
1.121 +/**
1.122 +@return True if a directory error has been found
1.123 +*/
1.124 +TBool CScanDrive::IsDirError()const
1.125 + {
1.126 + return(iDirError!=0);
1.127 + }
1.128 +
1.129 +
1.130 +
1.131 +/**
1.132 + After StartL() and finishing allows us to know if there were any problems at all.
1.133 + The client may wish to remount the filesystem if there were errors.
1.134 +
1.135 + @return EFalse if there were no problems in FS.
1.136 +*/
1.137 +TBool CScanDrive::ProblemsDiscovered() const
1.138 +{
1.139 + return IsDirError() || iFoundProblems;
1.140 +}
1.141 +
1.142 +/**
1.143 + Sets the flag indicating than there are errors in filesystem structure
1.144 + See ProblemsDiscovered()
1.145 +*/
1.146 +void CScanDrive::IndicateErrorsFound()
1.147 +{
1.148 + iFoundProblems = ETrue;
1.149 +}
1.150 +
1.151 +
1.152 +
1.153 +/**
1.154 +Start point for scan drive also fixes up errors
1.155 +
1.156 +@return The result of the scan
1.157 +@leave
1.158 +*/
1.159 +TInt CScanDrive::StartL()
1.160 + {
1.161 + __PRINT(_L("CScanDrive::StartL"));
1.162 + // check directory structure
1.163 + CheckDirStructureL();
1.164 +#if defined(DEBUG_SCANDRIVE)
1.165 + CompareFatsL();
1.166 +#endif
1.167 + // fix error in directory structure
1.168 + if(IsDirError())
1.169 + FixupDirErrorL();
1.170 + // flush new fat
1.171 + WriteNewFatsL();
1.172 +#if defined(DEBUG_SCANDRIVE)
1.173 + PrintErrors();
1.174 +#endif
1.175 + return KErrNone;
1.176 + }
1.177 +
1.178 +/**
1.179 +Fix errors detected by the drive scan
1.180 +
1.181 +@leave System wide error code
1.182 +*/
1.183 +void CScanDrive::FixupDirErrorL()
1.184 + {
1.185 + if(!IsDirError())
1.186 + return;
1.187 + if(iDirError==EScanMatchingEntry)
1.188 + {
1.189 + FindSameStartClusterL();
1.190 + FixMatchingEntryL();
1.191 + }
1.192 + else
1.193 + {
1.194 + FixPartEntryL();
1.195 + }
1.196 +
1.197 + IndicateErrorsFound(); //-- indicate that we have found errors
1.198 + }
1.199 +
1.200 +/**
1.201 +Find positions of entries with same start cluster for error correction, searches
1.202 +the whole volume. Starts at the root directory.
1.203 +
1.204 +@leave System wide error code
1.205 +*/
1.206 +void CScanDrive::FindSameStartClusterL()
1.207 + {
1.208 + TInt err=FindStartClusterL(0);
1.209 + if(err==KErrNone)
1.210 + return;
1.211 + for(TInt i=0;i<KMaxArrayDepth && iClusterListArray[i]!=NULL;++i)
1.212 + {
1.213 + RArray<TInt>* clusterList=iClusterListArray[i];
1.214 + for(TInt j=0;j<clusterList->Count();++j)
1.215 + {
1.216 + iRecursiveDepth=0;
1.217 + err=FindStartClusterL((*clusterList)[j]);
1.218 + if(err==KErrNone)
1.219 + return;
1.220 + }
1.221 + }
1.222 + __ASSERT_ALWAYS(err==KErrNone,User::Leave(KErrNotFound));
1.223 + }
1.224 +/**
1.225 +Scan through directory structure looking for start cluster found in iMatching
1.226 +
1.227 +@param aDirCluster Start cluster for scan to start
1.228 +@return System wide error value
1.229 +@leave
1.230 +*/
1.231 +TInt CScanDrive::FindStartClusterL(TInt aDirCluster)
1.232 + {
1.233 + __PRINT1(_L("CScanDrive::FindStartCluster dirCluster=%d"),aDirCluster);
1.234 + __ASSERT_ALWAYS(aDirCluster>=0,User::Leave(KErrCorrupt));
1.235 + if(++iRecursiveDepth==KMaxScanDepth)
1.236 + {
1.237 + --iRecursiveDepth;
1.238 + return(KErrNotFound);
1.239 + }
1.240 + TEntryPos entryPos(aDirCluster,0);
1.241 + TInt dirEntries=0;
1.242 + FOREVER
1.243 + {
1.244 + TFatDirEntry entry;
1.245 + iMount->ReadDirEntryL(entryPos,entry);
1.246 + if(entry.IsParentDirectory()||entry.IsCurrentDirectory()||entry.IsErased())
1.247 + {
1.248 + if(IsEndOfRootDir(entryPos))
1.249 + break;
1.250 + iMount->MoveToNextEntryL(entryPos);
1.251 + continue;
1.252 + }
1.253 + if(entry.IsEndOfDirectory())
1.254 + break;
1.255 + TBool isComplete;
1.256 + TEntryPos vfatPos=entryPos;
1.257 + isComplete=MoveToVFatEndL(entryPos,entry,dirEntries);
1.258 + __ASSERT_ALWAYS(isComplete,User::Leave(KErrBadName));
1.259 + TInt err=CheckEntryClusterL(entry,vfatPos);
1.260 + if(err==KErrNone)
1.261 + {
1.262 + --iRecursiveDepth;
1.263 + return(err);
1.264 + }
1.265 + if(IsEndOfRootDir(entryPos))
1.266 + break;
1.267 + iMount->MoveToNextEntryL(entryPos);
1.268 + }
1.269 + --iRecursiveDepth;
1.270 + return(KErrNotFound);
1.271 + }
1.272 +
1.273 +/**
1.274 +Procces aEntry to find matching start cluster
1.275 +
1.276 +@param aEntry Directory entry to check
1.277 +@param aEntryPos Position of directory to check
1.278 +@return System wide error value
1.279 +@leave
1.280 +*/
1.281 +TInt CScanDrive::CheckEntryClusterL(const TFatDirEntry& aEntry, const TEntryPos& aEntryPos)
1.282 + {
1.283 + __PRINT(_L("CScanDrive::CheckEntryClusterL"));
1.284 + if(iMount->StartCluster(aEntry)==iMatching.iStartCluster)
1.285 + {
1.286 + TBool complete=AddMatchingEntryL(aEntryPos);
1.287 + if(complete)
1.288 + return(KErrNone);
1.289 + }
1.290 + else if(aEntry.Attributes()&KEntryAttDir)
1.291 + return(FindStartClusterL(iMount->StartCluster(aEntry)));
1.292 + return(KErrNotFound);
1.293 + }
1.294 +
1.295 +/**
1.296 +Checks directory strucutre for errors, can be considered the start point of the scan.
1.297 +Handles recursion depth to avoid stack overflow.
1.298 +
1.299 +@leave System wide error code
1.300 +*/
1.301 +void CScanDrive::CheckDirStructureL()
1.302 + {
1.303 + CheckDirL(iMount->RootIndicator());
1.304 + // Due to recursive nature of CheckDirL when a depth of
1.305 + // KMaxScanDepth is reached clusters are stored in a list
1.306 + // and passed into CheckDirL afresh
1.307 + for(TInt i=0;i<KMaxArrayDepth && iClusterListArray[i]!=NULL;++i)
1.308 + {
1.309 + RArray<TInt>* clusterList=iClusterListArray[i];
1.310 + ++iListArrayIndex;
1.311 + for(TInt j=0;j<clusterList->Count();++j)
1.312 + {
1.313 + iRecursiveDepth=0;
1.314 + CheckDirL((*clusterList)[j]);
1.315 + }
1.316 + }
1.317 + }
1.318 +/**
1.319 +Function is called recursively with Process entry untill the whole volume has been scanned.
1.320 +Each directory entry is scanned for errors, these are recorded for later fixing.
1.321 +
1.322 +@param aCluster Directory cluster to start checking
1.323 +@leave System wide error codes
1.324 +*/
1.325 +void CScanDrive::CheckDirL(TInt aCluster)
1.326 + {
1.327 + __PRINT1(_L("CScanDrive::CheckDirL aCluster=%d"),aCluster);
1.328 + __ASSERT_ALWAYS(aCluster>=0,User::Leave(KErrCorrupt));
1.329 + // check depth of recursion
1.330 + if(++iRecursiveDepth==KMaxScanDepth)
1.331 + {
1.332 + AddToClusterListL(aCluster);
1.333 + --iRecursiveDepth;
1.334 + return;
1.335 + }
1.336 +#if defined(DEBUG_SCANDRIVE)
1.337 + ++iDirsChecked;
1.338 +#endif
1.339 + TEntryPos entryPos(aCluster,0);
1.340 + TInt dirEntries=0;
1.341 + FOREVER
1.342 + {
1.343 + TFatDirEntry entry;
1.344 + iMount->ReadDirEntryL(entryPos,entry);
1.345 + if(!iMount->IsEndOfClusterCh(entryPos.iCluster))
1.346 + ++dirEntries;
1.347 + if(entry.IsParentDirectory()||entry.IsCurrentDirectory()||entry.IsErased())
1.348 + {
1.349 + if(IsEndOfRootDir(entryPos))
1.350 + break;
1.351 + iMount->MoveToNextEntryL(entryPos);
1.352 + continue;
1.353 + }
1.354 + if(entry.IsEndOfDirectory())
1.355 + {
1.356 + if(aCluster)
1.357 + WriteClusterChainL(aCluster,dirEntries<<KSizeOfFatDirEntryLog2);
1.358 + break;
1.359 + }
1.360 + TEntryPos origPos=entryPos;
1.361 + TFatDirEntry origEntry=entry;
1.362 + TInt origDirEntries=dirEntries;
1.363 + TBool isComplete;
1.364 + isComplete=MoveToVFatEndL(entryPos,entry,dirEntries);
1.365 + // Only assume that this is a corrupted VFAT entry if the VFAT attributes are set;
1.366 + // assuming a non-VFAT corrupted entry is a VFAT entry is dangerous as we then assume that the
1.367 + // first byte is a count of entries to skip, thus completely invalidating the next <n> directories.
1.368 + if (!isComplete && origEntry.IsVFatEntry())
1.369 + {
1.370 + AddPartialVFatL(origPos,origEntry);
1.371 + if(entryPos.iCluster!=KEndOfDirectory)
1.372 + {
1.373 + TInt toMove=origEntry.NumFollowing()-(dirEntries-origDirEntries);
1.374 + if(toMove)
1.375 + MovePastEntriesL(entryPos,entry,toMove,dirEntries);
1.376 + }
1.377 + else
1.378 + {
1.379 + // we fell off the end of the directory file, so just strip this
1.380 + // incomplete long file name entry
1.381 + dirEntries = origDirEntries;
1.382 + }
1.383 + }
1.384 + else
1.385 + ProcessEntryL(entry);
1.386 + if(IsEndOfRootDir(entryPos))
1.387 + break;
1.388 + iMount->MoveToNextEntryL(entryPos);
1.389 + }
1.390 + --iRecursiveDepth;
1.391 + }
1.392 +
1.393 +/**
1.394 +Process non trivial entries, such as files, if they are correct by filling out their
1.395 +cluster allocation in the bit packed Fat table. If it comes accross a directory
1.396 +CheckDirL will be called.
1.397 +
1.398 +@param aEntry Directory entry to check
1.399 +@leave System wide error code
1.400 +*/
1.401 +void CScanDrive::ProcessEntryL(const TFatDirEntry& aEntry)
1.402 + {
1.403 + __PRINT(_L("CScanDrive::ProcessEntryL"));
1.404 + TInt entryAtt=aEntry.Attributes();
1.405 + __ASSERT_ALWAYS(!(entryAtt&~KEntryAttMaskSupported)&&!aEntry.IsErased(),User::Leave(KErrCorrupt));
1.406 + if(!(entryAtt&(KEntryAttDir|KEntryAttVolume)) && iMount->StartCluster(aEntry)>0)
1.407 + WriteClusterChainL(iMount->StartCluster(aEntry),aEntry.Size());
1.408 + else if(entryAtt&KEntryAttDir)
1.409 + CheckDirL(iMount->StartCluster(aEntry));
1.410 + }
1.411 +
1.412 +/**
1.413 +Writes out the cluster chain for a correct file or directory, checks that the cluster
1.414 +has not already been used and that the correct number of clusters are allocated for the
1.415 +size of file. Registers cluster as used if correct
1.416 +
1.417 +@param aCluster Cluster chain start point
1.418 +@param aSizeInBytes Size of the file or directory in bytes
1.419 +@leave System wide error values
1.420 +*/
1.421 +void CScanDrive::WriteClusterChainL(TInt aCluster,TInt aSizeInBytes)
1.422 +//
1.423 +// Mark off in the new fat the clusters used by entry with start cluster of aCluster
1.424 +//
1.425 + {
1.426 +
1.427 + IndicateErrorsFound(); //-- indicate that we have found errors
1.428 +
1.429 + __PRINT1(_L("CScanDrive::WriteClusterChainL starting at %d"),aCluster);
1.430 + __ASSERT_ALWAYS(aCluster>0 && aSizeInBytes>=0,User::Leave(KErrCorrupt));
1.431 + TInt clusterCount;
1.432 + if(aSizeInBytes==0)
1.433 + clusterCount=1;
1.434 + else
1.435 + clusterCount=(aSizeInBytes+(1<<iMount->ClusterSizeLog2())-1)>>iMount->ClusterSizeLog2();
1.436 + TInt startCluster=aCluster;
1.437 + while(clusterCount)
1.438 + {
1.439 + if(AlreadyExistsL(aCluster))
1.440 + {
1.441 + __ASSERT_ALWAYS(!IsDirError()&&iMatching.iStartCluster==0&&aCluster==startCluster,User::Leave(KErrCorrupt));
1.442 + iMatching.iStartCluster=aCluster;
1.443 + iDirError=EScanMatchingEntry;
1.444 + return;
1.445 + }
1.446 + if(clusterCount==1)
1.447 + {
1.448 + iNewFat->WriteFatEntryEofFL(aCluster);
1.449 + return;
1.450 + }
1.451 + else
1.452 + {
1.453 + TInt clusterVal;
1.454 + clusterVal=iMount->FAT().ReadL(aCluster);
1.455 + __ASSERT_ALWAYS(!IsEofF(clusterVal) && clusterVal!=0,User::Leave(KErrCorrupt));
1.456 + iNewFat->WriteL(aCluster,clusterVal);
1.457 + aCluster=clusterVal;
1.458 + --clusterCount;
1.459 + }
1.460 + }
1.461 + }
1.462 +
1.463 +/**
1.464 +Move to dos entry, checking all vfat entry ID numbers are in sequence.
1.465 +Assumes aEntry is not erased
1.466 +
1.467 +@param aPos Position of the entry to move from, returns with new position
1.468 +@param aEntry The Dos entry after the Vfat entries on return
1.469 +@param aDirLength Running total of the length of the directory in entries
1.470 +@leave System wide error codes
1.471 +@return EFalse if not valid vfat entries or dos entry, else returns ETrue
1.472 +*/
1.473 +TBool CScanDrive::MoveToVFatEndL(TEntryPos& aPos,TFatDirEntry& aEntry,TInt& aDirLength)
1.474 + {
1.475 + __PRINT2(_L("CScanDrive::MoveToVFatEndL cluster=%d,pos=%d"),aPos.iCluster,aPos.iPos);
1.476 + if(!aEntry.IsVFatEntry())
1.477 + return IsDosEntry(aEntry);
1.478 + TInt toFollow=aEntry.NumFollowing();
1.479 + __ASSERT_ALWAYS(toFollow>0&&!aEntry.IsErased(),User::Leave(KErrCorrupt));
1.480 + FOREVER
1.481 + {
1.482 + iMount->MoveToNextEntryL(aPos);
1.483 + iMount->ReadDirEntryL(aPos,aEntry);
1.484 + ++aDirLength;
1.485 + --toFollow;
1.486 + if(!toFollow)
1.487 + break;
1.488 + if(!IsValidVFatEntry(aEntry,toFollow))
1.489 + return(EFalse);
1.490 + }
1.491 + return(IsDosEntry(aEntry));
1.492 + }
1.493 +
1.494 +/**
1.495 +Check if an entry is valid VFat
1.496 +
1.497 +@param aEntry Entry to check
1.498 +@param aPrevNum Number into VFat entries for a dos entry to ensure in correct position
1.499 +@return ETrue if aEntry is a valid vfat entry
1.500 +*/
1.501 +TBool CScanDrive::IsValidVFatEntry(const TFatDirEntry& aEntry, TInt aPrevNum)const
1.502 + {
1.503 + if(aEntry.IsErased()||!aEntry.IsVFatEntry())
1.504 + return(EFalse);
1.505 + return(aEntry.NumFollowing()==aPrevNum);
1.506 + }
1.507 +
1.508 +/**
1.509 +Check if an entry is a Dos entry
1.510 +
1.511 +@param aEntry Entry to check
1.512 +@return ETrue if aEntry is a dos entry
1.513 +*/
1.514 +TBool CScanDrive::IsDosEntry(const TFatDirEntry& aEntry)const
1.515 + {
1.516 + TBool res = !(aEntry.Attributes()&~KEntryAttMaskSupported) && !aEntry.IsErased() && !aEntry.IsVFatEntry() && !aEntry.IsEndOfDirectory();
1.517 + return res;
1.518 + }
1.519 +
1.520 +/**
1.521 +Add partial entry to iPartEntry under the error condition of not all Vfat entries
1.522 +being present
1.523 +
1.524 +@param aStartPos Position of the Dos entry associated with the VFat entries
1.525 +@param aEntry Directory Entry of the Dos entry associated with the VFat entries
1.526 +@leave KErrCorrupt Occurs if the entry is not valid
1.527 +*/
1.528 +void CScanDrive::AddPartialVFatL(const TEntryPos& aStartPos, const TFatDirEntry& aEntry)
1.529 + {
1.530 + __PRINT2(_L("CScanDrive::AddPartialVFatL cluster=%d pos=%d"),aStartPos.iCluster,aStartPos.iPos);
1.531 + __ASSERT_ALWAYS(!IsDirError(),User::Leave(KErrCorrupt));
1.532 + iPartEntry.iEntryPos=aStartPos;
1.533 + iPartEntry.iEntry=aEntry;
1.534 + iDirError=EScanPartEntry;
1.535 + }
1.536 +
1.537 +/**
1.538 +Add entry position to iMatching
1.539 +
1.540 +@param aEntryPos Position of the entry with the matching entry
1.541 +@leave KErrCorrupt if the start cluster is 0 or more that two matching entries occurs
1.542 +@return
1.543 +*/
1.544 +TBool CScanDrive::AddMatchingEntryL(const TEntryPos& aEntryPos)
1.545 + {
1.546 + __PRINT2(_L("CScanDrive::AddMatchingEntryL cluster=%d pos=%d"),aEntryPos.iCluster,aEntryPos.iPos);
1.547 + __ASSERT_ALWAYS(iMatching.iStartCluster>0 && iMatching.iCount<KMaxMatchingEntries,User::Leave(KErrCorrupt));
1.548 + iMatching.iEntries[iMatching.iCount++]=aEntryPos;
1.549 + return iMatching.iCount==KMaxMatchingEntries;
1.550 + }
1.551 +
1.552 +
1.553 +/**
1.554 +Scan for differnces in the new and old FAT table writing them to media if discovered
1.555 +
1.556 +@leave System wide error codes
1.557 +*/
1.558 +void CScanDrive::WriteNewFatsL()
1.559 +//
1.560 +// Write the new fat table to disk
1.561 +//
1.562 + {
1.563 + if(iNewFat->FlushL())
1.564 + IndicateErrorsFound(); //-- indicate that we have found errors
1.565 + }
1.566 +
1.567 +TInt CScanDrive::GetReservedidL(TEntryPos aVFatPos)
1.568 +//
1.569 +// Return the id found in reserved2 field of dos entry
1.570 +//
1.571 + {
1.572 + __PRINT(_L("CScanDrive::GetReservedidL"));
1.573 + TFatDirEntry entry;
1.574 + iMount->ReadDirEntryL(aVFatPos,entry);
1.575 + if(!IsDosEntry(entry))
1.576 + {
1.577 + TInt toMove=entry.NumFollowing();
1.578 + while(toMove--)
1.579 + iMount->MoveToNextEntryL(aVFatPos);
1.580 + iMount->ReadDirEntryL(aVFatPos,entry);
1.581 + }
1.582 + return(entry.RuggedFatEntryId());
1.583 + }
1.584 +
1.585 +/**
1.586 +Erase part entry found in iPartEntry
1.587 +
1.588 +@leave System wide error code
1.589 +*/
1.590 +void CScanDrive::FixPartEntryL()
1.591 + {
1.592 + __PRINT2(_L("CScanDrive::FixPartEntryL cluster=%d,pos=%d"),iPartEntry.iEntryPos.iCluster,iPartEntry.iEntryPos.iPos);
1.593 + iMount->EraseDirEntryL(iPartEntry.iEntryPos,iPartEntry.iEntry);
1.594 + IndicateErrorsFound(); //-- indicate that we have found errors
1.595 + }
1.596 +
1.597 +/**
1.598 +Delete entry with largest value in the reserved2 section(bytes 20 and 21) of dos entry
1.599 +
1.600 +@leave System wide error code
1.601 +*/
1.602 +void CScanDrive::FixMatchingEntryL()
1.603 + {
1.604 + __PRINT1(_L("CScanDrive::FixMatchingEntryL() start cluster=%d"),iMatching.iStartCluster);
1.605 + __ASSERT_ALWAYS(iMatching.iCount==KMaxMatchingEntries,User::Leave(KErrCorrupt));
1.606 + TInt idOne=GetReservedidL(iMatching.iEntries[0]);
1.607 + TInt idTwo=GetReservedidL(iMatching.iEntries[1]);
1.608 + TFatDirEntry entry;
1.609 + TInt num=idOne>idTwo?0:1;
1.610 + iMount->ReadDirEntryL(iMatching.iEntries[num],entry);
1.611 + iMount->EraseDirEntryL(iMatching.iEntries[num],entry);
1.612 + IndicateErrorsFound(); //-- indicate that we have found errors
1.613 + }
1.614 +/**
1.615 +Move past specified number of entries
1.616 +
1.617 +@param aEntryPos Start position to move from, updated as move takes place
1.618 +@param aEntry Directory entry moved to
1.619 +@param aToMove Number of entries to move through
1.620 +@param aDirEntries Number of entries moved, updated as move takes place
1.621 +@leave System wide error code
1.622 +*/
1.623 +void CScanDrive::MovePastEntriesL(TEntryPos& aEntryPos,TFatDirEntry& aEntry,TInt aToMove,TInt& aDirEntries)
1.624 + {
1.625 + while(aToMove-- && aEntryPos.iCluster!=KEndOfDirectory)
1.626 + {
1.627 + iMount->MoveToNextEntryL(aEntryPos);
1.628 + ++aDirEntries;
1.629 + }
1.630 + iMount->ReadDirEntryL(aEntryPos,aEntry);
1.631 + }
1.632 +
1.633 +/**
1.634 +Adds aCluster to cluster list array so that it may be revisited later, avoids stack
1.635 +over flow
1.636 +
1.637 +@param aCluster Directory cluster number to add to the list
1.638 +@leave KErrNoMemory If allocation fails
1.639 +*/
1.640 +void CScanDrive::AddToClusterListL(TInt aCluster)
1.641 + {
1.642 + if(iListArrayIndex>=KMaxArrayDepth)
1.643 + return;
1.644 + if(iClusterListArray[iListArrayIndex]==NULL)
1.645 + iClusterListArray[iListArrayIndex]=new(ELeave) RArray<TInt>(KClusterListGranularity);
1.646 + iClusterListArray[iListArrayIndex]->Append(aCluster);
1.647 + }
1.648 +
1.649 +
1.650 +#if defined(DEBUG_SCANDRIVE)
1.651 +void CScanDrive::CompareFatsL()
1.652 +//
1.653 +// Compare new fat and first fat table
1.654 +//
1.655 + {
1.656 + __PRINT(_L("CScanDrive::CompareFatsL()"));
1.657 + TInt maxClusters;
1.658 + maxClusters=iMount->UsableClusters();
1.659 + for(TInt i=KFatFirstSearchCluster; i<maxClusters; ++i)
1.660 + {
1.661 + TInt realFat=iMount->FAT().ReadL(i);
1.662 + TInt newFat=iNewFat->ReadL(i);
1.663 + if(realFat!=newFat)
1.664 + {
1.665 + if(realFat!=0 && newFat==0)
1.666 + __PRINT1(_L("Lost cluster=%d\n"),i)
1.667 + else if((realFat>0 && !IsEofF(realFat)) && IsEofF(newFat))
1.668 + __PRINT1(_L("Hanging cluster = %d\n"),i)
1.669 + else if(realFat==0 && newFat>0)
1.670 + __PRINT1(_L("Unflushed cluster = %d\n"),i)
1.671 + else
1.672 + User::Leave(KErrCorrupt);
1.673 + }
1.674 + }
1.675 + }
1.676 +
1.677 +
1.678 +/**
1.679 +For debug purposes, print errors found as debug output
1.680 +
1.681 +*/
1.682 +void CScanDrive::PrintErrors()
1.683 + {
1.684 + __PRINT1(_L("Directories visisted = %d\n"),iDirsChecked);
1.685 + if(iDirError==EScanPartEntry)
1.686 + __PRINT2(_L("Part entry-dir cluster=%d,dir pos=%d,\n"),iPartEntry.iEntryPos.iCluster,iPartEntry.iEntryPos.iPos)
1.687 + else if(iDirError==EScanMatchingEntry)
1.688 + {
1.689 + __PRINT1(_L("Matching cluster - cluster no=%d\n"),iMatching.iStartCluster);
1.690 + __PRINT2(_L("\tcluster 1 - dir cluster=%d,dir pos=%d\n"),iMatching.iEntries[0].iCluster,iMatching.iEntries[0].iPos);
1.691 + __PRINT2(_L("\tcluster 2 - dir cluster=%d,dir pos=%d\n"),iMatching.iEntries[1].iCluster,iMatching.iEntries[1].iPos);
1.692 + }
1.693 + }
1.694 +
1.695 +#endif
1.696 +
1.697 +
1.698 +
1.699 +