4147 return KErrNotSupported; |
4147 return KErrNotSupported; |
4148 } |
4148 } |
4149 |
4149 |
4150 //----------------------------------------------------------------------------------------- |
4150 //----------------------------------------------------------------------------------------- |
4151 |
4151 |
4152 //-- maximal level of recursion for the CheckDisk. i.e. the max. number of folded directories to check. |
4152 /** |
4153 const TInt KCheckDskMaxRecursionLevel = 50; |
4153 Check file system for errors. |
4154 |
4154 @return KErrNone if no errors found, otherwise a error code hopefully describing the problem found. |
4155 // |
4155 */ |
4156 // Walks a directory cluster list then checks all the entries. |
|
4157 // |
|
4158 void CFatMountCB::ChkDirL(RBitVector& aFatBitVec, TInt aDirCluster) |
|
4159 { |
|
4160 //__PRINT1(_L("### CFatMountCB::ChkDirL() level:%d"),iChkDiscRecLevel); |
|
4161 |
|
4162 //-- check if we have reached the recursion limit. on hardware the stack is very limited |
|
4163 //-- and its overflow will lead to crash. |
|
4164 if(iChkDiscRecLevel++ >= KCheckDskMaxRecursionLevel) |
|
4165 { |
|
4166 __PRINT1(_L("CFatMountCB::ChkDirL() max recursion level(%d) reached. Leaving!"),iChkDiscRecLevel); |
|
4167 User::Leave(KErrTooBig); |
|
4168 } |
|
4169 |
|
4170 if(/*Is32BitFat() &&*/aDirCluster != 0 && (aDirCluster == RootIndicator()))//the bit in comments maybe required |
|
4171 WalkClusterListL(aFatBitVec, RootIndicator()); |
|
4172 |
|
4173 TEntryPos entryPos(aDirCluster,0); |
|
4174 FOREVER |
|
4175 { |
|
4176 TFatDirEntry entry; |
|
4177 ReadDirEntryL(entryPos,entry); |
|
4178 MoveToDosEntryL(entryPos,entry); |
|
4179 if (entry.IsEndOfDirectory()) |
|
4180 break; |
|
4181 if (IsRootDir(entryPos)&&(StartOfRootDirInBytes()+entryPos.iPos==(RootDirEnd()-KSizeOfFatDirEntry))) |
|
4182 { |
|
4183 if(!entry.IsErased()) |
|
4184 ChkEntryL(aFatBitVec, entry); |
|
4185 break; // Allows maximum number of entries in root directory |
|
4186 } |
|
4187 MoveToNextEntryL(entryPos); |
|
4188 if (entry.IsParentDirectory() || entry.IsCurrentDirectory() || entry.IsErased()) |
|
4189 continue; |
|
4190 ChkEntryL(aFatBitVec, entry); |
|
4191 } |
|
4192 |
|
4193 iChkDiscRecLevel--; |
|
4194 } |
|
4195 |
|
4196 //----------------------------------------------------------------------------------------- |
|
4197 |
|
4198 // |
|
4199 // Check FAT is valid for anEntry |
|
4200 // |
|
4201 void CFatMountCB::ChkEntryL(RBitVector& aFatBitVec, const TFatDirEntry& anEntry) |
|
4202 { |
|
4203 TInt listLength=0; |
|
4204 |
|
4205 if ((anEntry.Attributes()&(KEntryAttDir)) || anEntry.Size()) |
|
4206 listLength=WalkClusterListL(aFatBitVec, StartCluster(anEntry)); |
|
4207 else if (anEntry.StartCluster() != 0) // zero length file |
|
4208 User::Leave(EFatChkDskInvalidEntrySize); // shouldn't have clusters |
|
4209 |
|
4210 if (anEntry.Attributes()&KEntryAttDir) |
|
4211 ChkDirL(aFatBitVec, StartCluster(anEntry)); |
|
4212 |
|
4213 // Check that the correct number of clusters have been allocated for the size of the file. |
|
4214 |
|
4215 else if ((anEntry.Attributes()&KEntryAttVolume)==0) |
|
4216 { |
|
4217 TInt clustersForFileSize; |
|
4218 TInt clusterSize=1<<ClusterSizeLog2(); |
|
4219 clustersForFileSize = (TInt) ( (TInt64(anEntry.Size()) + TInt64(clusterSize-1)) >> ClusterSizeLog2() ); |
|
4220 |
|
4221 if (listLength!=clustersForFileSize) |
|
4222 User::Leave(EFatChkDskInvalidEntrySize); |
|
4223 } |
|
4224 } |
|
4225 |
|
4226 //----------------------------------------------------------------------------------------- |
|
4227 |
|
4228 // |
|
4229 // Walks cluster list from aCluster to EOF |
|
4230 // Reports an error if an invalid cluster is found before EOF or |
|
4231 // a cluster has been visited before. |
|
4232 // |
|
4233 TInt CFatMountCB::WalkClusterListL(RBitVector& aFatBitVec, TInt aCluster) |
|
4234 { |
|
4235 |
|
4236 TInt i=0; |
|
4237 do { |
|
4238 i++; |
|
4239 if (!ValidClusterNumber(aCluster)) |
|
4240 { |
|
4241 __PRINT1(_L("Bad Cluster number %d"),aCluster); |
|
4242 User::Leave(EFatChkDskIllegalClusterNumber); |
|
4243 } |
|
4244 |
|
4245 if (IsClusterVisited(aFatBitVec, aCluster)) |
|
4246 { |
|
4247 __PRINT1(_L("Cluster already in use %d"),aCluster); |
|
4248 User::Leave(EFatChkDskClusterAlreadyInUse); |
|
4249 } |
|
4250 |
|
4251 MarkClusterVisited(aFatBitVec, aCluster); |
|
4252 |
|
4253 } while (FAT().GetNextClusterL(aCluster)); |
|
4254 |
|
4255 return(i); |
|
4256 } |
|
4257 |
|
4258 //----------------------------------------------------------------------------------------- |
|
4259 |
|
4260 // |
|
4261 // Checks that all unvisited clusters are marked as free in the FAT |
|
4262 // |
|
4263 void CFatMountCB::CheckUnvisitedClustersL(const RBitVector& aFatBitVec) const |
|
4264 { |
|
4265 |
|
4266 TInt cluster=2; |
|
4267 TInt maxCluster=cluster + UsableClusters(); |
|
4268 while (cluster<maxCluster) |
|
4269 { |
|
4270 cluster=NextUnvisitedCluster(aFatBitVec, cluster); //-- move to the next unvisited cluster |
|
4271 if(cluster < 0 || cluster >= maxCluster) |
|
4272 break; |
|
4273 |
|
4274 TInt clusterVal=FAT().ReadL(cluster); |
|
4275 if (clusterVal!=0 && IsEndOfClusterCh(clusterVal)==EFalse && !IsBadCluster(clusterVal)) |
|
4276 { |
|
4277 __PRINT1(_L("\n*****Bad cluster Num = %d"),cluster); |
|
4278 User::Leave(EFatChkDskBadCluster); |
|
4279 } |
|
4280 } |
|
4281 } |
|
4282 |
|
4283 //----------------------------------------------------------------------------------------- |
|
4284 |
|
4285 /** |
|
4286 @param aCluster cluster number to check for validity |
|
4287 @returns ETrue if aCluster is a valid cluster number |
|
4288 */ |
|
4289 TBool CFatMountCB::ValidClusterNumber(TUint32 aCluster) const |
|
4290 { |
|
4291 return (aCluster>=KFatFirstSearchCluster && aCluster<=MaxClusterNumber()); |
|
4292 } |
|
4293 |
|
4294 //----------------------------------------------------------------------------------------- |
|
4295 |
|
4296 // |
|
4297 // Walk the FAT, returns error if find an unterminated list or |
|
4298 // lists that merge. |
|
4299 // |
|
4300 TInt CFatMountCB::CheckDisk() |
4156 TInt CFatMountCB::CheckDisk() |
4301 { |
4157 { |
4302 |
4158 |
4303 __PRINT1(_L("CFatMountCB::CheckDisk() drv:%d"), DriveNumber()); |
4159 __PRINT1(_L("CFatMountCB::CheckDisk() drv:%d"), DriveNumber()); |
4304 |
4160 |
4305 if(!ConsistentState()) |
4161 if(!ConsistentState()) |
4306 return KErrCorrupt; |
4162 return KErrCorrupt; |
4307 |
4163 |
4308 //-- create a bit representation of the FAT |
4164 //-- create a bit representation of the FAT |
4309 const TUint32 MaxClusters = UsableClusters()+KFatFirstSearchCluster; //-- UsableClusters() doesn't count first 2 unused clusers |
4165 const TUint32 MaxClusters = UsableClusters()+KFatFirstSearchCluster; //-- UsableClusters() doesn't count first 2 unused clusers |
4310 |
|
4311 |
|
4312 // cluster count may be zero if boot sector failed to be read (e.g. if the media is locked) |
|
4313 // or if TDrive::MountMedia(ETrue) has been called (in which case the boot sector may |
|
4314 if (MaxClusters == 0) |
4166 if (MaxClusters == 0) |
4315 return KErrCorrupt; |
4167 return KErrCorrupt; |
4316 |
4168 |
4317 //-- used for measuring time |
4169 //-- used for measuring time |
4318 TTime timeStart; |
4170 TTime timeStart; |
4319 TTime timeEnd; |
4171 TTime timeEnd; |
4320 timeStart.UniversalTime(); //-- take start time |
4172 timeStart.UniversalTime(); //-- take start time |
4321 |
4173 |
4322 |
|
4323 RBitVector bitVec; //-- each bit in this vector represents a FAT cluster |
|
4324 |
|
4325 TInt nRes = bitVec.Create(MaxClusters); |
|
4326 if(nRes != KErrNone) |
|
4327 { |
|
4328 ASSERT(nRes == KErrNoMemory); //-- the only one possible reason. |
|
4329 return KErrNoMemory; |
|
4330 } |
|
4331 |
|
4332 iChkDiscRecLevel = 0; //-- reset CheckDisk recursion counter |
|
4333 TRAPD(r,ChkDirL(bitVec, RootIndicator())); // Check from root directory |
|
4334 if (r==KErrNone) |
|
4335 { |
|
4336 TRAP(r,CheckUnvisitedClustersL(bitVec)); |
|
4337 } |
|
4338 |
|
4339 |
|
4340 bitVec.Close(); |
|
4341 |
|
4342 timeEnd.UniversalTime(); //-- take end time |
|
4343 const TInt msScanTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec); |
|
4344 (void)msScanTime; |
|
4345 |
|
4346 __PRINT1(_L("#@@@ CheckDisk() time taken:%d ms"), msScanTime); |
|
4347 |
|
4348 |
|
4349 switch(r) |
|
4350 { |
|
4351 |
|
4352 case KErrNone: |
|
4353 return KErrNone; |
|
4354 |
|
4355 case EFatChkDskIllegalClusterNumber: |
|
4356 return(1); |
|
4357 |
|
4358 case EFatChkDskClusterAlreadyInUse: |
|
4359 return(2); |
|
4360 |
|
4361 case EFatChkDskBadCluster: |
|
4362 return(3); |
|
4363 |
|
4364 case EFatChkDskInvalidEntrySize: |
|
4365 return(4); |
|
4366 |
|
4367 default: |
|
4368 break; |
|
4369 } |
|
4370 |
|
4371 return(r); |
|
4372 } |
|
4373 |
|
4374 |
|
4375 //----------------------------------------------------------------------------------------- |
|
4376 // Helper functions for Check Disk functionality |
|
4377 //----------------------------------------------------------------------------------------- |
|
4378 |
|
4379 /** |
|
4380 Find the next unvisited cluster number in the bit array. |
|
4381 |
|
4382 @param aBitList bit array, where '0' bits represent unvisited clusters. |
|
4383 @param aCluster cluster number to start search with. |
|
4384 |
|
4385 @return positive integer indicating next unvisited cluster number |
|
4386 KErrNotFound (-1) if there are no unvisited clusters |
|
4387 |
|
4388 */ |
|
4389 static TInt NextUnvisitedCluster(const RBitVector& aFatBitVec, TUint32 aCluster) |
|
4390 { |
|
4391 __ASSERT_DEBUG(aCluster >= KFatFirstSearchCluster, Fault(EFatChkDskIllegalClusterNumber)); //-- 1st 2 FAT entries are reserved |
|
4392 |
|
4393 TUint32 searchPos = aCluster; //-- bit number to start search with |
|
4394 |
|
4395 //-- look for the unvisited cluster (bit '0') in the bit array from the searchPos to the right |
|
4396 if(aFatBitVec.Find(searchPos, 0, RBitVector::ERight)) |
|
4397 return searchPos; |
|
4398 |
|
4399 return KErrNotFound; |
|
4400 } |
|
4401 |
|
4402 |
|
4403 /** |
|
4404 Check if we have visited cluster aCluster |
|
4405 |
|
4406 @param aFatBitVec bit array, where '0' bits represent unvisited clusters. |
|
4407 @param aCluster cluster number to check |
|
4408 @return ETrue if aCluster has been visited. |
|
4409 */ |
|
4410 static TBool IsClusterVisited(const RBitVector& aFatBitVec, TUint32 aCluster) |
|
4411 { |
|
4412 __ASSERT_DEBUG(aCluster >= KFatFirstSearchCluster, Fault(EFatChkDskIllegalClusterNumber)); //-- 1st 2 FAT entries are reserved |
|
4413 |
|
4414 return aFatBitVec[aCluster]; |
|
4415 } |
|
4416 |
|
4417 /** |
|
4418 Mark aCluster as visited |
|
4419 @param aFatBitVec bit array, where '0' bits represent unvisited clusters. |
|
4420 @param aCluster cluster number to mark |
|
4421 */ |
|
4422 static void MarkClusterVisited(RBitVector& aFatBitVec, TUint32 aCluster) |
|
4423 { |
|
4424 __ASSERT_DEBUG(aCluster >= KFatFirstSearchCluster, Fault(EFatChkDskIllegalClusterNumber)); //-- 1st 2 FAT entries are reserved |
|
4425 |
|
4426 aFatBitVec.SetBit(aCluster); //-- '1' bit in a bit array means that the corresponding cluster is visited |
|
4427 } |
|
4428 |
|
4429 |
|
4430 |
|
4431 //------------------------------------------------------------------------------------------------------------------- |
|
4432 |
|
4433 /** |
|
4434 Creates a scan drive object and starts the scan. |
|
4435 */ |
|
4436 TInt CFatMountCB::DoRunScanDrive() |
|
4437 { |
|
4438 TInt nRes; |
4174 TInt nRes; |
4439 |
4175 |
4440 CScanDrive* pScnDrv = NULL; |
4176 CScanDrive* pScnDrv = NULL; |
4441 TRAP(nRes, pScnDrv=CScanDrive::NewL(this)); |
4177 TRAP(nRes, pScnDrv=CScanDrive::NewL(this)); |
4442 if(nRes != KErrNone) |
4178 if(nRes != KErrNone) |
4443 return nRes; |
4179 return nRes; |
4444 |
4180 |
4445 TRAPD(nScnDrvRes, pScnDrv->StartL()); |
4181 //-- start ScanDrive in "checkdisk" mode |
|
4182 TRAPD(nScnDrvRes, pScnDrv->StartL(CScanDrive::ECheckDisk)); |
|
4183 |
|
4184 timeEnd.UniversalTime(); //-- take end time |
|
4185 const TInt msScanTime = (TInt)( (timeEnd.MicroSecondsFrom(timeStart)).Int64() / K1mSec); |
|
4186 (void)msScanTime; |
|
4187 __PRINT1(_L("#@@@ CheckDisk() time taken:%d ms"), msScanTime); |
|
4188 |
|
4189 CScanDrive::TGenericError chkDskRes = pScnDrv->ProblemsDiscovered(); |
|
4190 const TBool bProblemsFound = (nScnDrvRes!=KErrNone) || pScnDrv->ProblemsDiscovered(); |
|
4191 |
|
4192 if(bProblemsFound && chkDskRes == CScanDrive::ENoErrors) |
|
4193 {//-- ScanDrive in this mode can leave unexpectedly without setting an error code that is returned by ProblemsDiscovered(); |
|
4194 //-- leave itself means a problem |
|
4195 chkDskRes = CScanDrive::EUnknownError; |
|
4196 } |
|
4197 |
|
4198 delete pScnDrv; |
|
4199 |
|
4200 if(chkDskRes != KErrNone) |
|
4201 { |
|
4202 __PRINT2(_L("CFatMountCB::CheckDisk() drv:%d, result:%d"), DriveNumber(), chkDskRes); |
|
4203 } |
|
4204 |
|
4205 return chkDskRes; |
|
4206 |
|
4207 } |
|
4208 |
|
4209 |
|
4210 //------------------------------------------------------------------------------------------------------------------- |
|
4211 |
|
4212 /** |
|
4213 Creates a scan drive object and starts the scan. |
|
4214 */ |
|
4215 TInt CFatMountCB::DoRunScanDrive() |
|
4216 { |
|
4217 TInt nRes; |
|
4218 |
|
4219 CScanDrive* pScnDrv = NULL; |
|
4220 TRAP(nRes, pScnDrv=CScanDrive::NewL(this)); |
|
4221 if(nRes != KErrNone) |
|
4222 return nRes; |
|
4223 |
|
4224 TRAPD(nScnDrvRes, pScnDrv->StartL(CScanDrive::EScanAndFix)); |
4446 |
4225 |
4447 const TBool bNeedFatRemount = (nScnDrvRes!=KErrNone) || pScnDrv->ProblemsDiscovered(); |
4226 const TBool bNeedFatRemount = (nScnDrvRes!=KErrNone) || pScnDrv->ProblemsDiscovered(); |
4448 delete pScnDrv; |
4227 delete pScnDrv; |
4449 |
4228 |
4450 |
4229 |