diff -r a179b74831c9 -r c1f20ce4abcf userlibandfileserver/fileserver/sfat32/sl_scan32.cpp --- a/userlibandfileserver/fileserver/sfat32/sl_scan32.cpp Thu Aug 19 11:14:22 2010 +0300 +++ b/userlibandfileserver/fileserver/sfat32/sl_scan32.cpp Tue Aug 31 16:34:26 2010 +0300 @@ -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. @@ -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 @@ -300,7 +301,6 @@ PrintErrors(); - timeEnd.UniversalTime(); //-- take end time const TInt elapsedTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec); (void)elapsedTime; @@ -478,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); @@ -763,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)); } //---------------------------------------------------------------------------------------------------- @@ -845,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 @@ -885,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 @@ -902,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; @@ -928,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); } //---------------------------------------------------------------------------------------------------- @@ -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()) {