diff -r a232af6b0b1f -r a5496987b1da userlibandfileserver/fileserver/sfat32/sl_scan32.cpp --- a/userlibandfileserver/fileserver/sfat32/sl_scan32.cpp Wed Jun 23 12:58:21 2010 +0100 +++ b/userlibandfileserver/fileserver/sfat32/sl_scan32.cpp Thu Jul 01 17:57:33 2010 +0100 @@ -72,10 +72,11 @@ ASSERT(aMount); //--- setting up - iMount=aMount; - iGenericError = ENoErrors; - iDirError = ENoDirError; - iMaxClusters = iMount->UsableClusters()+KFatFirstSearchCluster; //-- UsableClusters() doesn't count first 2 unused clusers + iMount = aMount; + iGenericError = ENoErrors; + iDirError = ENoDirError; + iHangingClusters = 0; + iMaxClusters = iMount->UsableClusters()+KFatFirstSearchCluster; //-- UsableClusters() doesn't count first 2 unused clusers //------------------------------ //-- create bit vectors that will represent FAT on media and reconstructed by ScanDrive. Each bit in the vector represents 1 FAT cluster. @@ -94,7 +95,7 @@ //---------------------------------------------------------------------------------------------------- /** FAT type-agnostic parser. Reads whole FAT and sets up a bit vector. - for FAT12/16 it's OK, because the FAT12/16 is fully cached. + For FAT12/16 it's OK, because the FAT12/16 is fully cached. */ void CScanDrive::DoParseFatL() { @@ -109,7 +110,7 @@ const TUint32 nFatEntry = ReadFatL(i); //-- each '1' bit represents a used cluster - if(nFatEntry != KSpareCluster) + if(nFatEntry != KSpareCluster) iMediaFatBits.SetBit(i); } } @@ -125,7 +126,7 @@ ASSERT((aBuf.Size() & (sizeof(TFat32Entry)-1)) == 0); const TInt KNumEntries = aBuf.Size() >> KFat32EntrySzLog2; - const TFat32Entry* const pFatEntry = (const TFat32Entry*)(aBuf.Ptr()); + const TFat32Entry* const pFatEntry = (const TFat32Entry*)(aBuf.Ptr()); for(TInt i=0; iLocalDrive()->Read(mediaPos, bytesToRead, buf)); + User::LeaveIfError(iMount->LocalDrive()->Read(mediaPos, bytesToRead, fatParseBuf)); //-- parse the buffer and populate bit vector DoParseFat32Buf(ptrData, currFatEntry); @@ -187,8 +188,8 @@ rem -= bytesToRead; } - buf.Close(); - CleanupStack::PopAndDestroy(&buf); + fatParseBuf.Close(); + CleanupStack::PopAndDestroy(&fatParseBuf); } @@ -241,7 +242,7 @@ } /** - Sets the flag indicating than there are errors in filesystem structure + Sets the flag indicating that there are errors in filesystem structure See ProblemsDiscovered() @param aError a code describing the error @@ -255,8 +256,9 @@ //---------------------------------------------------------------------------------------------------- /** - Start the scanner. The this calss description about what it actually does. - @param aMode specifies the operational mode. + Starts the scanner. + + @param aMode Specifies the operational mode. */ void CScanDrive::StartL(TScanDriveMode aMode) { @@ -299,7 +301,6 @@ PrintErrors(); - timeEnd.UniversalTime(); //-- take end time const TInt elapsedTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec); (void)elapsedTime; @@ -477,7 +478,7 @@ { CheckDirL(iMount->RootIndicator()); // Due to recursive nature of CheckDirL when a depth of - // KMaxScanDepth is reached clusters are stored in a list + // KMaxScanDepth is reached, clusters are stored in a list // and passed into CheckDirL afresh for(TUint i=0;iIsEndOfClusterCh(ReadFatL(aCluster))) - {//-- seems to be a rugged FAT artefact; File truncation/extension had failed before and now file length is less than - //-- the corresponding cluster chain shall be. It will be truncated to the size recorded in file DOS entry. - iTruncationCluster = aCluster; + { + // According to the directory entry, we have reached the end of the cluster chain, + // whereas in the media FAT, it is not. + // This is a rugged FAT artefact; hanging cluster chain: + // A cluster chain which is longer in the FAT table than is recorded in the corresponding directory entry + // or not terminated by an EOC entry in FAT. + // This is caused by: + // - File truncation failing. + // - OR file expanding failing during flushing to the media FAT. if(CheckDiskMode()) - {//-- in check disk mode this is a FS error; Indicate error and abort furter scanning - __PRINT1(_L("CScanDrive::RecordClusterChainL #2 %d"),aCluster); + {//-- in check disk mode this is an FS error; Indicate error and abort further scanning + __PRINT1(_L("CScanDrive::RecordClusterChainL #2 Hanging cluster=%d"),aCluster); IndicateErrorsFound(EInvalidEntrySize); User::Leave(KErrCorrupt); } + + // The chain will be truncated to the size recorded in the file's DOS entry and + // the remaining lost cluster chain will be fixed later in CompareAndFixFatsL(). + FixHangingClusterChainL(aCluster); } //__PRINT1(_L("#--: %d -> EOC"), aCluster); @@ -762,8 +773,8 @@ if(!IsValidVFatEntry(aEntry,toFollow)) return(EFalse); } - - return(IsDosEntry(aEntry)); + // A sequence of VFat entries must end with a Dos entry to be valid. + return(IsDosEntry(aEntry)); } //---------------------------------------------------------------------------------------------------- @@ -844,7 +855,7 @@ //---------------------------------------------------------------------------------------------------- /** - Scan for differnces in the new and old FAT table writing them to media if discovered + Scan for differences in the new and old FAT table writing them to media if discovered It is supposed to be called in 'ScanDrive' mode only @leave System wide error codes @@ -884,9 +895,10 @@ continue; } - //-- here we found a lost cluster. Its FAT entry will be replaced with KSpareCluster. In the case of multiple lost clusters FAT table will - //-- be flushed on media sector basis. It is much faster than flushing FAT after every write and will - //-- guarantee that FAT won't be corrupted if the media driver provides atomic sector write. + //-- Here we found a lost cluster. Its FAT entry will be replaced with KSpareCluster. + //-- In the case of multiple lost clusters FAT table will be flushed on media sector basis. + //-- It is much faster than flushing FAT after every write and will guarantee + //-- that FAT won't be corrupted if the media driver provides atomic sector write. if(nClustersFixed == 0) {//-- this is the first lost cluster entry we found @@ -901,7 +913,7 @@ const TUint32 fatSec = iMount->FAT().PosInBytes(i) >> KSectorSzLog2; if(fatSec != dirtyFatSector) - {//-- we are going to write to a differrent media sector + {//-- we are going to write to a different media sector iMount->FAT().FlushL(); iMount->FAT().WriteL(i, KSpareCluster); //-- fix lost cluster dirtyFatSector = fatSec; @@ -927,18 +939,11 @@ //------ - if(iTruncationCluster != 0) - { - iMount->FAT().WriteFatEntryEofL(iTruncationCluster); - iMount->FAT().FlushL(); - - //-- indicate that there are some problems in FAT. and we probably wrote something there. - IndicateErrorsFound(EScanDriveDirError); //-- indicate that we have found errors - - ++nClustersFixed; - } + + // Add the number of hanging clusters fixed by ScanDrive + nClustersFixed += iHangingClusters; - __PRINT2(_L("CScanDrive::WriteNewFatsL() fixed:%d, bad:%d"), nClustersFixed, nBadClusters); + __PRINT3(_L("CScanDrive::WriteNewFatsL() fixed clusters=%d,hanging clusters=%d,bad clusters=%d"),nClustersFixed,iHangingClusters,nBadClusters); } //---------------------------------------------------------------------------------------------------- @@ -946,7 +951,6 @@ Read the "Rugged FAT" ID, stored in reserved2 in the Dos entry or associated with the Dos entry of the Entry at the position passed in. This is used to find which version of two matching entries should be kept. - @param aVFatPos Position of an entry to read ID from @leave System wide error codes @return The ID found in reserved2 field of dos entry @@ -1015,6 +1019,28 @@ //---------------------------------------------------------------------------------------------------- /** + Fix a hanging cluster chain. + Writes EOF to the corresponding FAT entry, making this cluster chain length correspond to the + real file size recorded in the directory entry. + The remainder of the chain will be cleaned up later in CompareAndFixFatsL(). + + @leave System wide error code +*/ +void CScanDrive::FixHangingClusterChainL(TUint32 aFatEofIndex) + { + __PRINT1(_L("CScanDrive::FixHangingClusterL() Hanging cluster=%d"), aFatEofIndex); + + iMount->FAT().WriteFatEntryEofL(aFatEofIndex); + iMount->FAT().FlushL(); + iHangingClusters++; + + // Indicate that we have found an error + IndicateErrorsFound(EScanDriveDirError); + } + + +//---------------------------------------------------------------------------------------------------- +/** Move past specified number of entries @param aEntryPos Start position to move from, updated as move takes place @@ -1087,35 +1113,26 @@ if(BoolXOR(bRealFatEntry, bNewFatEntry)) {//-- mismatch between FAT on the media and the FAT bitmap restored by walking directory structure - if(bRealFatEntry) - {//-- FAT[i] on the media is marked as occupied, but retored FAT bitmap shows that it is free - if(iMount->IsBadCluster(ReadFatL(i))) - continue; //-- this is a BAD cluster it can't be occupied by the FS object, OK. + if(bRealFatEntry) + {//-- FAT[i] on the media is marked as occupied, but restored FAT bitmap shows that it is free + if(iMount->IsBadCluster(ReadFatL(i))) + continue; //-- this is a BAD cluster it can't be occupied by the FS object, OK. - __PRINT2(_L("FAT[%d] = %d\n"), i, ReadFatL(i)); - __PRINT1(_L("iTruncationCluster = %d\n"), iTruncationCluster); - - //-- this is a lost cluster - if(!IsEofF(ReadFatL(i)) && (i==iTruncationCluster)) - {//-- seems to be a Rugged FAT ertefact - __PRINT1(_L("Hanging cluster = %d\n"),i); - } - else - { - __PRINT1(_L("Lost cluster=%d\n"),i); - } - - - IndicateErrorsFound(EBadClusterValue); - } - else - {//-- FAT[i] on the media is marked as free, but retored FAT bitmap shows that it is occupied by some object - IndicateErrorsFound(EClusterAlreadyInUse); - __PRINT1(_L("Unflushed cluster = %d\n"),i); - } + __PRINT2(_L("FAT[%d] = %d\n"), i, ReadFatL(i)); + + //-- this is a Rugged FAT artefact; a lost cluster + __PRINT1(_L("Lost cluster=%d\n"),i); + + IndicateErrorsFound(EBadClusterValue); + } + else + {//-- FAT[i] on the media is marked as free, but restored FAT bitmap shows that it is occupied by some object + IndicateErrorsFound(EClusterAlreadyInUse); + __PRINT1(_L("Unflushed cluster = %d\n"),i); + } - if(aStopOnFirstErrorFound) - break; //-- not asked to check for errors further + if(aStopOnFirstErrorFound) + break; //-- not asked to check for errors further } @@ -1187,13 +1204,13 @@ } /** - Read a cluster from the Media Fat if scan run in a seperate thread read from scan fat table + Read a cluster from the Media Fat if scan run in a separate thread read from scan Fat table otherwise read from mount owned Fat table @param aClusterNum Cluster to read @return Value of cluster read from Fat */ -TUint32 CScanDrive::ReadFatL(TUint aClusterNum) +TUint32 CScanDrive::ReadFatL(TUint aClusterNum) { if(aClusterNum < KFatFirstSearchCluster || aClusterNum >= MaxClusters()) {