userlibandfileserver/fileserver/sfat32/sl_fatmisc32.cpp
changeset 0 a41df078684a
child 20 597aaf25e343
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // f32\sfat\sl_fatmisc32.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "sl_std.h"
       
    19 #include "sl_cache.h"
       
    20 
       
    21 /**
       
    22 @return ETrue if it is Fat32
       
    23 */
       
    24 TBool CFatFormatCB::Is32BitFat() const
       
    25 	{
       
    26 	return(iFileSystemName==KFileSystemName32);
       
    27 	}
       
    28 
       
    29 /**
       
    30 @return ETrue if it is Fat16
       
    31 */
       
    32 TBool CFatFormatCB::Is16BitFat() const
       
    33 	{
       
    34     return(iFileSystemName==KFileSystemName16);
       
    35     }
       
    36 
       
    37 /**
       
    38 Calculate the FAT size in sectors for a Fat32 volume
       
    39 
       
    40 @return The number of sectors
       
    41 */
       
    42 TUint32 CFatFormatCB::MaxFat32Sectors() const
       
    43 	{
       
    44 	TUint32 calc1 = iMaxDiskSectors - iReservedSectors;
       
    45 	TUint32 calc2 = (256 * iSectorsPerCluster) + iNumberOfFats;
       
    46 	calc2 = calc2 >> 1;
       
    47 	return (calc1 + (calc2 - 1))/calc2;
       
    48 	}
       
    49 
       
    50 
       
    51 const TUint KDefFatResvdSec = 1;    ///< default number of FAT12/16 reserved sectors
       
    52 const TUint KDefFat32ResvdSec = 32; ///< default number of FAT32 reserved sectors
       
    53 
       
    54 //-------------------------------------------------------------------------------------------------------------------
       
    55 void Dump_TLDFormatInfo(const TLDFormatInfo& aInfo)
       
    56 {
       
    57     (void)aInfo;
       
    58 #ifdef _DEBUG
       
    59     __PRINT(_L("----- TLDFormatInfo dump:"));
       
    60     __PRINT1(_L("iCapacity:%d"), aInfo.iCapacity);
       
    61     __PRINT1(_L("iSectorsPerCluster:%d"), aInfo.iSectorsPerCluster);
       
    62     __PRINT1(_L("iSectorsPerTrack:%d"), aInfo.iSectorsPerTrack);
       
    63     __PRINT1(_L("iFATBits:%d"), aInfo.iFATBits);
       
    64     __PRINT1(_L("iReservedSectors:%d"), aInfo.iReservedSectors);
       
    65     __PRINT1(_L("iFlags:%d"), aInfo.iFlags);
       
    66     __PRINT(_L("-----"));
       
    67 #endif
       
    68 }
       
    69 
       
    70 //-------------------------------------------------------------------------------------------------------------------
       
    71 
       
    72 /**
       
    73 Initialize the format parameters for a normal fixed sized disk
       
    74 Setting set to adhere to Rules of Count of clusters for FAT type
       
    75 
       
    76 @param  aDiskSizeInSectors Size of volume in sectors
       
    77 @return system-wide error code
       
    78 */
       
    79 TInt  CFatFormatCB::InitFormatDataForFixedSizeDiskNormal(TInt aDiskSizeInSectors, const TLocalDriveCapsV6& aCaps)
       
    80 	{
       
    81 	__PRINT1(_L("CFatFormatCB::InitFormatDataForFixedSizeDiskNormal() sectors:%d"), aDiskSizeInSectors);
       
    82     
       
    83     if( Drive().IsRemovable() )
       
    84 		iNumberOfFats = KNumberOfFatsExternal;
       
    85 	else
       
    86 		iNumberOfFats = KNumberOfFatsInternal;	
       
    87  	
       
    88 	iReservedSectors=KDefFatResvdSec;		
       
    89 	if (aDiskSizeInSectors <=4084*1)	// 2MB
       
    90 		{
       
    91 		iRootDirEntries=128;
       
    92 		iSectorsPerCluster=1;
       
    93 		iFileSystemName=KFileSystemName12;
       
    94 		iSectorsPerFat=MaxFat12Sectors();
       
    95    		}
       
    96 	else if (aDiskSizeInSectors<4084*2) // < 4MB (8168 sectors)
       
    97 		{
       
    98 		iRootDirEntries=256; 
       
    99 		iSectorsPerCluster=2;
       
   100 		iFileSystemName=KFileSystemName12;
       
   101 		iSectorsPerFat=MaxFat12Sectors();
       
   102 		}
       
   103 	else if (aDiskSizeInSectors<4084*4) // < 8MB (16336 sectors)
       
   104 		{
       
   105 		iRootDirEntries=512;
       
   106 		iSectorsPerCluster=4;
       
   107 		iFileSystemName=KFileSystemName12;
       
   108 		iSectorsPerFat=MaxFat12Sectors();
       
   109 		}
       
   110 	else if (aDiskSizeInSectors<4084*8) // < 16MB (32672 sectors)
       
   111 		{
       
   112 		iRootDirEntries=512;
       
   113 		iSectorsPerCluster=8;
       
   114 		iFileSystemName=KFileSystemName12;
       
   115 		iSectorsPerFat=MaxFat12Sectors();
       
   116 		}
       
   117 	else if(aDiskSizeInSectors<1048576) // >= 16Mb - FAT16   < (1048576) 512MB
       
   118 		{
       
   119 		iFileSystemName=KFileSystemName16;
       
   120 		TInt minSectorsPerCluster=(aDiskSizeInSectors+KMaxFAT16Entries-1)/KMaxFAT16Entries;
       
   121 		iRootDirEntries=512;
       
   122 		iSectorsPerCluster=1;
       
   123 		while (minSectorsPerCluster>iSectorsPerCluster)
       
   124 			iSectorsPerCluster<<=1;
       
   125 		iSectorsPerFat=MaxFat16Sectors();
       
   126 		}
       
   127 	else	//use FAT32
       
   128 		{
       
   129 		iFileSystemName=KFileSystemName32;
       
   130 		iRootDirEntries=0;						//this is always the case for fat32
       
   131 		if(aDiskSizeInSectors < 16777216)		//8GB in 512byte sectors
       
   132 			iSectorsPerCluster=8;
       
   133 		else if(aDiskSizeInSectors < 33554432)	//16GB in 512byte sectors
       
   134 			iSectorsPerCluster=16;
       
   135 		else if(aDiskSizeInSectors < 67108864)	//32GB in 512byte sectors 
       
   136 			iSectorsPerCluster=32;
       
   137 		else
       
   138 			iSectorsPerCluster=64;				//Anything >= 32GB uses a 32K cluster size
       
   139 		iReservedSectors=KDefFat32ResvdSec;
       
   140 		iRootClusterNum=2;						//As recomended in the document
       
   141 		iSectorsPerFat=MaxFat32Sectors();
       
   142 		
       
   143 		}
       
   144 
       
   145 	// Ensure cluster size is a multiple of the block size
       
   146 	TInt blockSizeInSectors = aCaps.iBlockSize >> iSectorSizeLog2;
       
   147 	__PRINT1(_L("blockSizeInSectors: %d"),blockSizeInSectors);
       
   148 	ASSERT(blockSizeInSectors == 0 || IsPowerOf2(blockSizeInSectors));
       
   149 	if (blockSizeInSectors != 0 && IsPowerOf2(blockSizeInSectors))
       
   150 		{
       
   151 		__PRINT1(_L("iSectorsPerCluster	(old): %d"),iSectorsPerCluster);
       
   152 		AdjustClusterSize(blockSizeInSectors);
       
   153 		__PRINT1(_L("iSectorsPerCluster	(new): %d"),iSectorsPerCluster);
       
   154 		}
       
   155 
       
   156 	// Align first data sector on an erase block boundary if
       
   157 	// (1) the iEraseBlockSize is specified
       
   158 	// (2) the start of the partition is already aligned to an erase block boundary, 
       
   159 	//     i.e. iHiddenSectors is zero or a multiple of iEraseBlockSize
       
   160 	__PRINT1(_L("iHiddenSectors: %d"),iHiddenSectors);
       
   161 	TInt eraseblockSizeInSectors = aCaps.iEraseBlockSize >> iSectorSizeLog2;
       
   162 	__PRINT1(_L("eraseblockSizeInSectors: %d"),eraseblockSizeInSectors);
       
   163 	ASSERT(eraseblockSizeInSectors == 0 || IsPowerOf2(eraseblockSizeInSectors));	
       
   164 	ASSERT(eraseblockSizeInSectors == 0 || eraseblockSizeInSectors >= blockSizeInSectors);
       
   165 	if ((eraseblockSizeInSectors != 0) &&
       
   166 		(iHiddenSectors % eraseblockSizeInSectors == 0) &&	
       
   167 		(IsPowerOf2(eraseblockSizeInSectors)) &&
       
   168 		(eraseblockSizeInSectors >= blockSizeInSectors))
       
   169 		{
       
   170 		TInt r = AdjustFirstDataSectorAlignment(eraseblockSizeInSectors);
       
   171 		ASSERT(r == KErrNone);
       
   172 		(void) r;
       
   173 		}
       
   174 	__PRINT1(_L("iReservedSectors: %d"),iReservedSectors);
       
   175 	__PRINT1(_L("FirstDataSector: %d"), FirstDataSector());
       
   176 
       
   177     return KErrNone;
       
   178 	}
       
   179 
       
   180 TInt CFatFormatCB::FirstDataSector() const
       
   181 	{
       
   182 	TInt rootDirSectors = (iRootDirEntries * KSizeOfFatDirEntry + (iBytesPerSector-1)) / iBytesPerSector;
       
   183     return iHiddenSectors + iReservedSectors + iNumberOfFats*iSectorsPerFat + rootDirSectors;
       
   184 	}
       
   185 
       
   186 void CFatFormatCB::AdjustClusterSize(TInt aRecommendedSectorsPerCluster)
       
   187 	{
       
   188     const TInt KMaxSecPerCluster = 64;	// 32K
       
   189 	while (aRecommendedSectorsPerCluster > iSectorsPerCluster && iSectorsPerCluster <= (KMaxSecPerCluster/2))
       
   190 		iSectorsPerCluster<<= 1;
       
   191 	}
       
   192 
       
   193 // AdjustFirstDataSectorAlignment()
       
   194 // Attempts to align the first data sector on an erase block boundary by modifying the
       
   195 // number of reserved sectors.
       
   196 TInt CFatFormatCB::AdjustFirstDataSectorAlignment(TInt aEraseBlockSizeInSectors)
       
   197 	{
       
   198 	const TBool bFat16 = Is16BitFat();
       
   199     const TBool bFat32 = Is32BitFat();
       
   200 
       
   201 	// Save these 2 values in the event of a convergence failure; this should 
       
   202 	// hopefully never happen, but we will cater for this in release mode to be safe,
       
   203 	TInt reservedSectorsSaved = iReservedSectors;
       
   204 	TInt sectorsPerFatSaved = iSectorsPerFat;
       
   205 
       
   206 	TInt reservedSectorsOld = 0;
       
   207 
       
   208 	// zero for FAT32
       
   209 	TInt rootDirSectors = (iRootDirEntries * KSizeOfFatDirEntry + (iBytesPerSector-1)) / iBytesPerSector;
       
   210 	TInt fatSectors = 0;
       
   211 
       
   212 	TInt KMaxIterations = 10;
       
   213 	TInt n;
       
   214 	for (n=0; n<KMaxIterations && reservedSectorsOld != iReservedSectors; n++)
       
   215 		{
       
   216 		reservedSectorsOld = iReservedSectors;
       
   217 
       
   218 		iSectorsPerFat = bFat32 ? MaxFat32Sectors() : bFat16 ? MaxFat16Sectors() : MaxFat12Sectors();
       
   219 
       
   220 		fatSectors = iSectorsPerFat * iNumberOfFats;
       
   221 
       
   222 		// calculate number of blocks
       
   223 		TInt  nBlocks = (iReservedSectors + fatSectors + rootDirSectors + aEraseBlockSizeInSectors-1) / aEraseBlockSizeInSectors;
       
   224 
       
   225 		iReservedSectors = (nBlocks * aEraseBlockSizeInSectors) - rootDirSectors - fatSectors;
       
   226 		}
       
   227 	
       
   228 	ASSERT(iReservedSectors >= (TInt) (bFat32 ? KDefFat32ResvdSec : KDefFatResvdSec));
       
   229 
       
   230 	if ((FirstDataSector() & (aEraseBlockSizeInSectors-1)) == 0)
       
   231 		{
       
   232 		return KErrNone;
       
   233 		}
       
   234 	else
       
   235 		{
       
   236 		iReservedSectors = reservedSectorsSaved;
       
   237 		iSectorsPerFat = sectorsPerFatSaved;
       
   238 		return KErrGeneral;
       
   239 		}
       
   240 	}
       
   241 
       
   242 
       
   243 //-------------------------------------------------------------------------------------------------------------------
       
   244 
       
   245 /**
       
   246 Create the boot sector on media for the volume. For FAT32 also creates a backup copy of the boot sector.
       
   247 
       
   248 @leave System wide error codes
       
   249 */
       
   250 void CFatFormatCB::CreateBootSectorL()
       
   251 	{
       
   252 	__PRINT1(_L("CFatFormatCB::CreateBootSector() drive:%d"),DriveNumber());
       
   253 
       
   254 	
       
   255     const TBool bFat32 = Is32BitFat();
       
   256     
       
   257     TFatBootSector bootSector;
       
   258 
       
   259 	bootSector.SetVendorID(KDefaultVendorID);
       
   260 	bootSector.SetBytesPerSector(iBytesPerSector);
       
   261 	bootSector.SetSectorsPerCluster(iSectorsPerCluster);
       
   262 	bootSector.SetReservedSectors(iReservedSectors);
       
   263 	bootSector.SetNumberOfFats(iNumberOfFats);
       
   264 	iCountOfClusters=iMaxDiskSectors/iSectorsPerCluster;
       
   265 	if (!bFat32)
       
   266 		{
       
   267 		if (iCountOfClusters>(TInt)KMaxTUint16)
       
   268 			User::Leave(KErrTooBig);
       
   269 		}
       
   270 
       
   271 	bootSector.SetReservedByte(0);
       
   272 	TTime timeID;
       
   273 	timeID.HomeTime();						//	System time in future?
       
   274 	bootSector.SetUniqueID(I64LOW(timeID.Int64()));	//	Generate UniqueID from time
       
   275 	bootSector.SetVolumeLabel(_L8(""));
       
   276 	bootSector.SetFileSysType(iFileSystemName);
       
   277 // Floppy specific info:
       
   278 	bootSector.SetJumpInstruction();
       
   279 	bootSector.SetMediaDescriptor(KBootSectorMediaDescriptor);
       
   280 	bootSector.SetNumberOfHeads(iNumberOfHeads);
       
   281 	bootSector.SetHiddenSectors(iHiddenSectors);
       
   282 	bootSector.SetSectorsPerTrack(iSectorsPerTrack);
       
   283 	bootSector.SetPhysicalDriveNumber(128);
       
   284 	bootSector.SetExtendedBootSignature(0x29);
       
   285 
       
   286 	if(bFat32)
       
   287 		{
       
   288 		bootSector.SetFatSectors(0);
       
   289 		bootSector.SetFatSectors32(iSectorsPerFat);
       
   290 		bootSector.SetRootDirEntries(0);
       
   291 		bootSector.SetTotalSectors(0);
       
   292 		bootSector.SetHugeSectors(iMaxDiskSectors);
       
   293 		bootSector.SetFATFlags(0);			
       
   294 		bootSector.SetVersionNumber(0x00);	
       
   295 		bootSector.SetRootClusterNum(iRootClusterNum);
       
   296 		bootSector.SetFSInfoSectorNum(KFSInfoSectorNum);	
       
   297         bootSector.SetBkBootRecSector(KBkBootSectorNum);
       
   298 		}
       
   299 	else//fat12 and 16
       
   300 		{
       
   301 		bootSector.SetFatSectors32(0);
       
   302 		bootSector.SetFatSectors(iSectorsPerFat);
       
   303 		bootSector.SetRootDirEntries(iRootDirEntries);
       
   304 
       
   305 		if (iMaxDiskSectors<=(TInt)KMaxTUint16)
       
   306 			{
       
   307 			bootSector.SetTotalSectors(iMaxDiskSectors);
       
   308 			bootSector.SetHugeSectors(0);
       
   309 			}
       
   310 		else
       
   311 			{
       
   312 			bootSector.SetTotalSectors(0);
       
   313 			bootSector.SetHugeSectors(iMaxDiskSectors);
       
   314 			}
       
   315 		}
       
   316 
       
   317 	//-- write main boot sector to the first sector on media
       
   318     User::LeaveIfError(FatMount().DoWriteBootSector(KBootSectorNum*bootSector.BytesPerSector(), bootSector));
       
   319 	
       
   320     //-- for FAT32 write backup copy of the boot sector
       
   321     if(bFat32)
       
   322         {
       
   323         User::LeaveIfError(FatMount().DoWriteBootSector(KBkBootSectorNum*bootSector.BytesPerSector(), bootSector));    
       
   324         }
       
   325 
       
   326     }
       
   327 
       
   328 //-------------------------------------------------------------------------------------------------------------------
       
   329 
       
   330 /**
       
   331 Format a disk section, called iteratively to erase whole of media, on last iteration
       
   332 creates an empty volume. If called with quick formatonly erases the Fat leaving the
       
   333 rest of the volume intact.
       
   334 
       
   335 @leave System wide error code
       
   336 */
       
   337 void CFatFormatCB::DoFormatStepL()
       
   338 	{
       
   339 	if (iFormatInfo.iFormatIsCurrent==EFalse)
       
   340 		{ // Only done first time through
       
   341 		if (iMode & EForceErase)
       
   342 			{
       
   343 			TInt r = FatMount().ErasePassword();
       
   344 			User::LeaveIfError(r);
       
   345 			// CFatMountCB::ErasePassword() calls TBusLocalDrive::ForceRemount(),
       
   346 			// so need to stop a remount from occurring in next call to :
       
   347 			// TFsFormatNext::DoRequestL((), TDrive::CheckMount().
       
   348 			FatMount().Drive().SetChanged(EFalse);
       
   349 			}
       
   350 
       
   351         RecordOldInfoL();
       
   352 		InitializeFormatDataL();
       
   353 		FatMount().DoDismount();
       
   354 		if (iVariableSize)
       
   355 			FatMount().ReduceSizeL(0,I64LOW(FatMount().iSize));
       
   356 		}
       
   357     //
       
   358     // Blank disk if not EQuickFormat
       
   359     //
       
   360 	if (!iVariableSize && !(iMode & EQuickFormat) && iCurrentStep)
       
   361 		{
       
   362 		if (iFormatInfo.iFormatIsCurrent == EFalse)
       
   363 			{//-- firstly invalidate sectors 0-6 inclusive, they may contain main boot sector, backup boot sector and FSInfo sector.
       
   364 	        DoZeroFillMediaL(0, (KBkBootSectorNum+1)*iBytesPerSector);
       
   365             }
       
   366 		TInt ret=FatMount().LocalDrive()->Format(iFormatInfo);
       
   367 		if (ret!=KErrNone && ret!=KErrEof) // Handle format error
       
   368             ret = HandleCorrupt(ret);
       
   369 
       
   370         if (ret!=KErrNone && ret!=KErrEof) // KErrEof could be set by LocalDrive()->Format()
       
   371 		    User::Leave(ret);
       
   372 
       
   373 		if (ret==KErrNone)
       
   374 			{
       
   375 			iCurrentStep = I64LOW( 100 - (100 * TInt64(iFormatInfo.i512ByteSectorsFormatted)) / iMaxDiskSectors );
       
   376 			if (iCurrentStep<=0)
       
   377 				iCurrentStep=1;
       
   378 			return;
       
   379 			}
       
   380 		}
       
   381 
       
   382 	// ReMount since MBR may have been rewritten and partition may have moved / changed size
       
   383 	TInt ret = LocalDrive()->ForceRemount(0);
       
   384 	if (ret != KErrNone && ret != KErrNotSupported)
       
   385 		User::Leave(ret);
       
   386 
       
   387 	// MBR may have changed, so need to re-read iHiddenSectors etc.before BPB is written
       
   388 	InitializeFormatDataL();
       
   389 
       
   390     // Translate bad sector number to cluster number which contains that sector
       
   391     // This only happens in full format, in quick format they are already cluster numbers
       
   392     if (!iVariableSize && !(iMode & EQuickFormat))
       
   393         User::LeaveIfError(BadSectorToCluster());
       
   394 
       
   395 	//Check if root cluster is bad and update as required
       
   396 	if(Is32BitFat() && !iVariableSize && (iMode & EQuickFormat))
       
   397 		{
       
   398 		if(iBadClusters.Find(iRootClusterNum) !=  KErrNotFound)
       
   399 			{
       
   400 			iRootClusterNum++;
       
   401             while(iBadClusters.Find(iRootClusterNum) != KErrNotFound)
       
   402 				{
       
   403 				iRootClusterNum++;
       
   404 				}
       
   405 			}
       
   406 		}
       
   407 
       
   408     //
       
   409     // Do the rest of the disk in one lump
       
   410     //
       
   411 	iCurrentStep=0;
       
   412 
       
   413     //-- zero-fill media from position 0 to the FAT end, i.e main & backup boot sector, FSInfo and its copy and all FATs
       
   414     const TUint32 posFatEnd = ((iSectorsPerFat*iNumberOfFats) + iReservedSectors) * iBytesPerSector; //-- last FAT end position
       
   415 	
       
   416     if (iVariableSize)
       
   417 		FatMount().EnlargeL(posFatEnd); 
       
   418 
       
   419     DoZeroFillMediaL(0, posFatEnd);
       
   420     
       
   421     if(Is32BitFat())
       
   422 		{//create an empty root directory entry here
       
   423 		
       
   424         const TUint KFat32EntrySz = 4; //-- FAT32 entry size, bytes
       
   425         const TInt  startFAT1   = iReservedSectors;              //-- FAT1 start sector
       
   426         const TInt  entryOffset = iRootClusterNum*KFat32EntrySz; //-- Root dir entry offset in the FAT, bytes
       
   427 
       
   428 		TBuf8<KFat32EntrySz> EOF(KFat32EntrySz);
       
   429 		EOF[0]=0xFF;		
       
   430 		EOF[1]=0xFF;
       
   431 		EOF[2]=0xFF;
       
   432 		EOF[3]=0x0F;
       
   433 
       
   434         //-- write EOF mark to the every FAT copy
       
   435     	for(TInt i=0; i<iNumberOfFats; i++)
       
   436             {
       
   437 		    const TInt rootDirEntryPos = iBytesPerSector*(startFAT1 + i*iSectorsPerFat) + entryOffset;
       
   438             User::LeaveIfError(LocalDrive()->Write(rootDirEntryPos, EOF));
       
   439             }
       
   440 
       
   441         //-- zero-fill FAT32 root directory (just 1 cluster)
       
   442 		const TInt firstDataSector = iReservedSectors + (iNumberOfFats * iSectorsPerFat); //+RootDirSectors (not required for fat32)
       
   443         const TInt firstSectorOfCluster = ((iRootClusterNum - KFatFirstSearchCluster) * iSectorsPerCluster) + firstDataSector;
       
   444 	
       
   445         const TUint32 posRootDirStart = firstSectorOfCluster * iBytesPerSector;
       
   446         const TUint32 posRootDirEnd = posRootDirStart + iSectorsPerCluster*iBytesPerSector;
       
   447 
       
   448         DoZeroFillMediaL(posRootDirStart, posRootDirEnd);
       
   449         }
       
   450 	else
       
   451 		{//-- FAT12/16
       
   452 		    //-- Zero fill root directory
       
   453             const TInt rootDirSector = iReservedSectors + (iNumberOfFats * iSectorsPerFat); 
       
   454             const TInt rootDirSize   = iRootDirEntries * KSizeOfFatDirEntry; //-- size in bytes
       
   455             
       
   456             const TUint32 posRootDirStart = rootDirSector * iBytesPerSector;
       
   457             const TUint32 posRootDirEnd   = posRootDirStart + rootDirSize;
       
   458 
       
   459             const TInt numOfRootSectors=(rootDirSize%iBytesPerSector) ? (rootDirSize/iBytesPerSector+1) : (rootDirSize/iBytesPerSector);
       
   460 		    if (iVariableSize)
       
   461 			    FatMount().EnlargeL(iBytesPerSector*numOfRootSectors);
       
   462 
       
   463             DoZeroFillMediaL(posRootDirStart, posRootDirEnd);
       
   464 
       
   465 		// Enlarge ram drive to take into account rounding of
       
   466 		// data start to cluster boundary
       
   467 		if(iVariableSize && iSectorsPerCluster!=1)
       
   468 			{
       
   469 			const TInt firstFreeSector=rootDirSector+numOfRootSectors;
       
   470 			const TInt firstFreeCluster=firstFreeSector%iSectorsPerCluster ? firstFreeSector/iSectorsPerCluster+1 : firstFreeSector/iSectorsPerCluster;
       
   471 			const TInt alignedSector=firstFreeCluster*iSectorsPerCluster;
       
   472 			if(alignedSector!=firstFreeSector)
       
   473 				FatMount().EnlargeL((alignedSector-firstFreeSector)*iBytesPerSector);
       
   474 			}
       
   475 		}
       
   476 
       
   477     //-- FAT[0] must contain media descriptor in the low byte, FAT[1] for fat16/32 may contain some flags
       
   478 	TBuf8<8> startFat(8);
       
   479     startFat.Fill(0xFF);
       
   480    
       
   481     if(Is32BitFat()) //-- FAT32
       
   482         {//-- FAT32 uses only low 28 bits in FAT entry. 
       
   483         startFat[3] = 0x0F;
       
   484         startFat[7] = 0x0F;
       
   485         } 
       
   486     else if(iVariableSize||Is16BitFat()) //-- FAT16 or RAM drive which is always FAT16
       
   487         {
       
   488         startFat.SetLength(4);
       
   489         }
       
   490     else //-- FAT12
       
   491         {
       
   492         startFat.SetLength(3);
       
   493         }
       
   494 
       
   495     startFat[0]=KBootSectorMediaDescriptor;
       
   496 
       
   497     //-- write FAT[0] and FAT[1] entries to all copies of FAT
       
   498 	for(TInt i=0;i<iNumberOfFats;i++)
       
   499         {
       
   500 		User::LeaveIfError(LocalDrive()->Write(iBytesPerSector*(iReservedSectors+(iSectorsPerFat*i)),startFat));
       
   501         }
       
   502 
       
   503 	//-- create boot sectors
       
   504     CreateBootSectorL();
       
   505 
       
   506     //-- create FSInfo sectors
       
   507     if (Is32BitFat())
       
   508 		{
       
   509 		CreateReservedBootSectorL();
       
   510         CreateFSInfoSectorL();
       
   511 		}
       
   512 
       
   513     //-- here we have bad clusters numbers saved by the quick format
       
   514     //-- Interpret old bad cluster number to new cluster number and mark new bad clusters
       
   515     if (!iVariableSize && iBadClusters.Count()>0)
       
   516         {
       
   517  	
       
   518         //-- Here we need fully mounted volume, so mount it normally.
       
   519 	    FatMount().MountL(EFalse);
       
   520 
       
   521         iBadClusters.Sort();
       
   522         TranslateL();
       
   523         const TInt mark = FatMount().Is32BitFat() ? KBad_32Bit : (FatMount().Is16BitFat() ? KBad_16Bit : KBad_12Bit);
       
   524         
       
   525         for (TInt i=0; i<iBadClusters.Count(); ++i)
       
   526             FatMount().FAT().WriteL(iBadClusters[i], mark);
       
   527         
       
   528         FatMount().FAT().FlushL();
       
   529         
       
   530         //-- indicate that the volume is "dirty" in order to the next Mount evend not to use FSInfo, which
       
   531         //-- contains incorrect value of free clusters because we already have bad ones saved.  
       
   532         //-- This is a very rare condition.
       
   533         FatMount().SetVolumeCleanL(EFalse); 
       
   534 
       
   535 #if defined(_DEBUG)
       
   536 	TInt r=FatMount().CheckDisk();
       
   537 	__PRINT1(_L("CFatFormatCB::DoFormatStepL() CheckDisk res: %d"),r);
       
   538 #endif
       
   539         }
       
   540         else
       
   541         {
       
   542         //-- We do not need to perform full mount in this case, the TDrive object will be marked as changed in ~CFormatCB and the
       
   543         //-- mount will be closed. Therefore on the first access to it it will be mounted normally.
       
   544         FatMount().MountL(ETrue); //-- force mount
       
   545         }
       
   546 
       
   547     __PRINT1(_L("CFatFormatCB::DoFormatStepL() Format complete drv:%d"), DriveNumber());
       
   548 	}
       
   549 
       
   550 
       
   551 //-------------------------------------------------------------------------------------------------------------------
       
   552 
       
   553 /**
       
   554     Initialize the user specific format parameters for fixed sized disk.
       
   555     
       
   556     @param  aDiskSizeInSectors disk size in sectors
       
   557     @return system-wide error code
       
   558 */
       
   559 TInt CFatFormatCB::InitFormatDataForFixedSizeDiskUser(TInt aDiskSizeInSectors)
       
   560 	{
       
   561     __PRINT1(_L("CFatFormatCB::InitFormatDataForFixedSizeDiskUser() sectors:%d"), aDiskSizeInSectors);
       
   562     Dump_TLDFormatInfo(iSpecialInfo());
       
   563 
       
   564     //-- KErrArgument will be returned if iSpecialInfo().iFATBits isn't one of EFB32, EFB16, EFB32
       
   565 
       
   566     if(iSpecialInfo().iFlags & TLDFormatInfo::EOneFatTable)
       
   567 		iNumberOfFats = 1;
       
   568     else if(iSpecialInfo().iFlags & TLDFormatInfo::ETwoFatTables)
       
   569 		iNumberOfFats = 2;
       
   570     else if(Drive().IsRemovable())
       
   571 		iNumberOfFats = KNumberOfFatsExternal;
       
   572 	else
       
   573 		iNumberOfFats = KNumberOfFatsInternal;
       
   574 
       
   575 
       
   576     if(iSpecialInfo().iReservedSectors == 0)
       
   577         iReservedSectors = KDefFatResvdSec; //-- user hasn't specified reserved sectors count, use default (FAT12/16)
       
   578     else
       
   579         iReservedSectors = iSpecialInfo().iReservedSectors;
       
   580 
       
   581 
       
   582     const TInt KMaxSecPerCluster    = 64; 
       
   583 	const TInt KDefaultSecPerCluster= 8;   //-- default value, if the iSpecialInfo().iSectorsPerCluster isn't specified
       
   584 
       
   585     iSectorsPerCluster = iSpecialInfo().iSectorsPerCluster;
       
   586     if(iSectorsPerCluster <= 0)
       
   587         {//-- default value, user hasn't specified TLDFormatInfo::iSectorsPerCluster
       
   588         iSectorsPerCluster = KDefaultSecPerCluster; //-- will be adjusted later
       
   589         }
       
   590     else
       
   591         {
       
   592         iSectorsPerCluster = Min(1<<Log2(iSectorsPerCluster), KMaxSecPerCluster);
       
   593 	    }
       
   594 
       
   595     //-----------------------------------------
       
   596 
       
   597     if (aDiskSizeInSectors < 4096) // < 2MB
       
   598         {
       
   599         iSectorsPerCluster = 1;
       
   600 		iRootDirEntries = 128;
       
   601         }
       
   602 	else if (aDiskSizeInSectors < 8192) // < 4MB
       
   603         {
       
   604         iSectorsPerCluster = Min(iSectorsPerCluster, 2);
       
   605 		iRootDirEntries = 256;
       
   606         }
       
   607 	else if (aDiskSizeInSectors < 32768) // < 16MB
       
   608         {
       
   609         iSectorsPerCluster = Min(iSectorsPerCluster, 4);
       
   610 		iRootDirEntries = 512;
       
   611         }
       
   612 	else if (aDiskSizeInSectors < 1048576) // < 512MB
       
   613         {
       
   614         iSectorsPerCluster = Min(iSectorsPerCluster, 8);
       
   615 		iRootDirEntries = 512;
       
   616         }
       
   617     else // FAT32
       
   618 		{
       
   619         iRootDirEntries = 512;
       
   620         iSectorsPerCluster = Min(iSectorsPerCluster, KMaxSecPerCluster);
       
   621         }
       
   622 
       
   623 
       
   624     //-----------------------------------------
       
   625 
       
   626 	TLDFormatInfo::TFATBits fatBits = iSpecialInfo().iFATBits;
       
   627 	if (fatBits == TLDFormatInfo::EFBDontCare)
       
   628 		{
       
   629         const TFatType fatType = SuggestFatType();
       
   630 		switch(fatType)
       
   631 			{
       
   632 			case EFat12:
       
   633 				fatBits = TLDFormatInfo::EFB12;
       
   634 				break;
       
   635 			case EFat16:
       
   636 				fatBits = TLDFormatInfo::EFB16;
       
   637 				break;
       
   638 			case EFat32:
       
   639 				fatBits = TLDFormatInfo::EFB32;
       
   640 				break;
       
   641 			case EInvalid:
       
   642 				ASSERT(0);
       
   643 			}
       
   644 		}
       
   645 
       
   646     TFatType reqFatType(EInvalid); //-- requested FAT type
       
   647 
       
   648     switch (fatBits)
       
   649 		{
       
   650 		case TLDFormatInfo::EFB12:
       
   651 			iFileSystemName=KFileSystemName12;
       
   652 			iSectorsPerFat=MaxFat12Sectors();
       
   653 			reqFatType = EFat12;
       
   654             break;
       
   655 
       
   656 		case TLDFormatInfo::EFB16:
       
   657 			iFileSystemName=KFileSystemName16;
       
   658 			iSectorsPerFat=MaxFat16Sectors();
       
   659 			reqFatType = EFat16;
       
   660             break;
       
   661 
       
   662 		case TLDFormatInfo::EFB32:
       
   663 			iFileSystemName=KFileSystemName32;
       
   664 			iSectorsPerFat=MaxFat32Sectors();
       
   665 	        
       
   666 			iRootDirEntries = 0;
       
   667 			iRootClusterNum = 2;
       
   668 			
       
   669             if(iSpecialInfo().iReservedSectors == 0)
       
   670                 iReservedSectors = KDefFat32ResvdSec; //-- user hasn't specified reserved sectors count, use default (FAT32)
       
   671             else
       
   672                 iReservedSectors = iSpecialInfo().iReservedSectors;
       
   673 
       
   674 			reqFatType = EFat32;
       
   675             break;
       
   676 
       
   677         default:
       
   678             __PRINT(_L("CFatFormatCB::InitFormatDataForFixedSizeDiskUser() Incorrect FAT type specifier!"));
       
   679             return KErrArgument;
       
   680 		}
       
   681 	
       
   682         //-- check if we can format the volume with requested FAT type
       
   683         const TFatType fatType = SuggestFatType();
       
   684         if(fatType != reqFatType)
       
   685 			{
       
   686 			//-- volume metrics don't correspond to the requested FAT type
       
   687             __PRINT(_L("CFatFormatCB::InitFormatDataForFixedSizeDiskUser() FAT type mismatch!"));
       
   688             return KErrArgument;
       
   689 			}
       
   690 
       
   691         return KErrNone;
       
   692     }
       
   693 
       
   694 /**
       
   695     Initialize the format parameters for a custom fixed sized disk
       
   696 
       
   697     @param  aFormatInfo The custom format parameters
       
   698     @return system-wide error code
       
   699 */
       
   700 TInt CFatFormatCB::InitFormatDataForFixedSizeDiskCustom(const TLDFormatInfo& aFormatInfo)
       
   701 	{
       
   702     __PRINT(_L("CFatFormatCB::InitFormatDataForFixedSizeDiskCustom()"));
       
   703     Dump_TLDFormatInfo(aFormatInfo);
       
   704 
       
   705 	if(aFormatInfo.iFlags & TLDFormatInfo::EOneFatTable)
       
   706 		iNumberOfFats = 1;
       
   707     else if(aFormatInfo.iFlags & TLDFormatInfo::ETwoFatTables)
       
   708 		iNumberOfFats = 2;
       
   709     else if(Drive().IsRemovable())
       
   710 		iNumberOfFats = KNumberOfFatsExternal;
       
   711 	else
       
   712 		iNumberOfFats = KNumberOfFatsInternal;	
       
   713 
       
   714 	iRootDirEntries=512;
       
   715 
       
   716 	iSectorsPerCluster = aFormatInfo.iSectorsPerCluster;
       
   717 	iSectorsPerTrack   = aFormatInfo.iSectorsPerTrack;
       
   718 	iNumberOfHeads	   = aFormatInfo.iNumberOfSides;
       
   719 	iReservedSectors   = aFormatInfo.iReservedSectors ? aFormatInfo.iReservedSectors : KDefFatResvdSec;
       
   720 	
       
   721     switch (aFormatInfo.iFATBits)
       
   722 		{
       
   723 		case TLDFormatInfo::EFB12:
       
   724 			iFileSystemName = KFileSystemName12;
       
   725 			iSectorsPerFat  = MaxFat12Sectors();
       
   726 			break;
       
   727 
       
   728 		case TLDFormatInfo::EFB16:
       
   729 			iFileSystemName = KFileSystemName16;
       
   730 			iSectorsPerFat  = MaxFat16Sectors();
       
   731             break;
       
   732 
       
   733 		case TLDFormatInfo::EFB32:
       
   734 			iFileSystemName  = KFileSystemName32;
       
   735 			iReservedSectors = aFormatInfo.iReservedSectors ? aFormatInfo.iReservedSectors : KDefFat32ResvdSec;
       
   736 			iSectorsPerFat   = MaxFat32Sectors();
       
   737 			iRootDirEntries  = 0;
       
   738 			iRootClusterNum  = 2;
       
   739             break;
       
   740 
       
   741 		default:
       
   742 			{
       
   743 			TInt64 clusters64 = (aFormatInfo.iCapacity / KDefaultSectorSize) / iSectorsPerCluster;
       
   744 			TInt clusters = I64LOW(clusters64);
       
   745 			if (clusters < 4085)
       
   746 				{
       
   747 				iFileSystemName = KFileSystemName12;
       
   748 				iSectorsPerFat  = MaxFat12Sectors();
       
   749 				}
       
   750 			else if(clusters < 65525)
       
   751 				{
       
   752 				iFileSystemName = KFileSystemName16;
       
   753 				iSectorsPerFat  = MaxFat16Sectors();
       
   754                 }
       
   755 			else
       
   756 				{
       
   757 				iFileSystemName  = KFileSystemName32;
       
   758 				iReservedSectors = aFormatInfo.iReservedSectors ? aFormatInfo.iReservedSectors : KDefFat32ResvdSec;
       
   759 				iSectorsPerFat   = MaxFat32Sectors();
       
   760 				iRootDirEntries  = 0;
       
   761 				iRootClusterNum  = 2;
       
   762 				}
       
   763 			}
       
   764 		}
       
   765 
       
   766     return KErrNone;
       
   767 	}
       
   768 
       
   769 void CFatFormatCB::RecordOldInfoL()
       
   770     {
       
   771     // Check if mount or disk is corrupt
       
   772     // This should be stored in member variable because FatMount is remounted
       
   773     //  every time RFormat::Next() gets called thus FatMount().Initialised()
       
   774     //  will be inconsistent with previous state.
       
   775 	TLocalDriveCapsV3Buf caps;
       
   776 	User::LeaveIfError(LocalDrive()->Caps(caps));
       
   777 	iVariableSize=((caps().iMediaAtt)&KMediaAttVariableSize) ? (TBool)ETrue : (TBool)EFalse;
       
   778     iDiskCorrupt = !FatMount().ConsistentState();
       
   779     iBadClusters.Reset();
       
   780     iBadSectors.Reset();
       
   781     if (!iVariableSize && !iDiskCorrupt && (iMode&EQuickFormat))
       
   782         {
       
   783         iOldFirstFreeSector = FatMount().iFirstFreeByte>>FatMount().SectorSizeLog2();
       
   784         iOldSectorsPerCluster = FatMount().SectorsPerCluster();
       
   785 
       
   786         FatMount().FAT().InvalidateCacheL(); //-- invalidate whole FAT cache
       
   787 
       
   788         // Collect bad cluster information from current FAT table
       
   789         const TInt maxClusterNum = FatMount().UsableClusters() + KFatFirstSearchCluster;
       
   790         const TUint32 mark = FatMount().Is32BitFat() ? KBad_32Bit : (FatMount().Is16BitFat() ? KBad_16Bit : KBad_12Bit);
       
   791         
       
   792         for (TInt i=KFatFirstSearchCluster; i<maxClusterNum; ++i)
       
   793             {
       
   794             if (FatMount().FAT().ReadL(i) == mark)
       
   795                 iBadClusters.AppendL(i);
       
   796             }
       
   797         }
       
   798     }
       
   799 
       
   800 
       
   801 
       
   802 
       
   803 TInt CFatFormatCB::BadSectorToCluster()
       
   804     {
       
   805     TInt sizeofFatAndRootDir;
       
   806     if (iFileSystemName != KFileSystemName32)
       
   807 		sizeofFatAndRootDir = iSectorsPerFat*iNumberOfFats + ((iRootDirEntries*KSizeOfFatDirEntry+(1<<iSectorSizeLog2)-1)>>iSectorSizeLog2);
       
   808     else
       
   809         sizeofFatAndRootDir = (iRootClusterNum-2) * iSectorsPerCluster;
       
   810     TInt firstFreeSector = iReservedSectors + sizeofFatAndRootDir;
       
   811 
       
   812     // Check in rare case that corrupt in critical area
       
   813     // which includes bootsector, FAT table, (and root dir if not FAT32)
       
   814     TInt i, r;
       
   815     for (i=0; i<iBadSectors.Count(); ++i)
       
   816         {
       
   817         TInt badSector = iBadSectors[i];
       
   818         // Check in rare case that corrupt in critical area
       
   819         // which includes bootsector, FAT table, (and root dir if not FAT32)
       
   820         if (firstFreeSector > badSector)
       
   821             {
       
   822             if (badSector == 0) // Boot sector corrupt
       
   823                 return KErrCorrupt;
       
   824             if (iFileSystemName==KFileSystemName32 && badSector==1) // FSInfo corrupt
       
   825                 return KErrCorrupt;
       
   826             if (badSector < iReservedSectors) // Harmless in reserved area
       
   827                 continue;
       
   828             // Extend reserved area to cover bad sector
       
   829             iReservedSectors = badSector + 1;
       
   830             firstFreeSector = iReservedSectors + sizeofFatAndRootDir;
       
   831             continue;
       
   832             }
       
   833 
       
   834         // Figure out bad cluster number and record it
       
   835         TUint cluster = (badSector-firstFreeSector)/iSectorsPerCluster+2;
       
   836         if (iBadClusters.Find(cluster) == KErrNotFound)
       
   837             {
       
   838             if ((r=iBadClusters.Append(cluster)) != KErrNone)
       
   839                 return r;
       
   840             if (iFileSystemName==KFileSystemName32 && iRootClusterNum==cluster)
       
   841                 iRootClusterNum++;
       
   842             }
       
   843         }
       
   844     return KErrNone;
       
   845     }
       
   846 
       
   847 /**
       
   848 Create the File system information sector and its backup copy on a disk. 
       
   849 Note that CFatMountCB is still not in mounted state, so we can not rely on it.
       
   850 
       
   851 @leave System wide error codes
       
   852 */
       
   853 void CFatFormatCB::CreateFSInfoSectorL()
       
   854 	{
       
   855 	__PRINT1(_L("CFatFormatCB::CreateFSInfoSectorL() drv:%d"), DriveNumber());
       
   856 	
       
   857     ASSERT(Is32BitFat()); //-- Actually, CFatMount shall be in a consistent state.
       
   858 
       
   859     TFSInfo fsInfo;
       
   860 	TBuf8<KSizeOfFSInfo> fsInfoSecBuf;
       
   861     
       
   862     const TUint32 freeSectors  = iMaxDiskSectors - (iReservedSectors + (iNumberOfFats * iSectorsPerFat));
       
   863     const TUint32 freeClusters = (freeSectors / iSectorsPerCluster) - 1; //-- 1st cluster is taken by empty Root Dir on FAT32
       
   864     const TUint32 nextFreeClust = iRootClusterNum+1; 
       
   865 
       
   866     fsInfo.SetFreeClusterCount(freeClusters);
       
   867     fsInfo.SetNextFreeCluster(nextFreeClust);
       
   868 
       
   869     fsInfo.Externalize(fsInfoSecBuf); //-- put data to the sector buffer
       
   870 
       
   871     User::LeaveIfError(LocalDrive()->Write(KFSInfoSectorNum*iBytesPerSector, fsInfoSecBuf)); //-- main FSInfo Sector
       
   872     User::LeaveIfError(LocalDrive()->Write(KBkFSInfoSectorNum*iBytesPerSector, fsInfoSecBuf)); //-- Backup FSInfo Sector
       
   873 
       
   874 	}
       
   875 
       
   876 /**
       
   877 Create the reserved boot sector and its backup copy on a disk. 
       
   878 These are located at sectors 2 & 8
       
   879 
       
   880 @leave System wide error codes
       
   881 */
       
   882 void CFatFormatCB::CreateReservedBootSectorL()
       
   883 	{
       
   884 	__PRINT1(_L("CFatFormatCB::CreateReserveBootSectorL() drv:%d"), DriveNumber());
       
   885 	
       
   886     ASSERT(Is32BitFat());
       
   887 
       
   888     TFatBootSector bootSector;
       
   889 
       
   890 	User::LeaveIfError(FatMount().DoWriteBootSector(KReservedBootSectorNum*KDefaultSectorSize, bootSector));
       
   891 	User::LeaveIfError(FatMount().DoWriteBootSector(KBkReservedBootSectorNum*KDefaultSectorSize, bootSector));    
       
   892 	}
       
   893 
       
   894 
       
   895 
       
   896