diff -r 000000000000 -r a41df078684a userlibandfileserver/fileserver/sfat32/sl_fatmisc32.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/userlibandfileserver/fileserver/sfat32/sl_fatmisc32.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,896 @@ +// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// f32\sfat\sl_fatmisc32.cpp +// +// + +#include "sl_std.h" +#include "sl_cache.h" + +/** +@return ETrue if it is Fat32 +*/ +TBool CFatFormatCB::Is32BitFat() const + { + return(iFileSystemName==KFileSystemName32); + } + +/** +@return ETrue if it is Fat16 +*/ +TBool CFatFormatCB::Is16BitFat() const + { + return(iFileSystemName==KFileSystemName16); + } + +/** +Calculate the FAT size in sectors for a Fat32 volume + +@return The number of sectors +*/ +TUint32 CFatFormatCB::MaxFat32Sectors() const + { + TUint32 calc1 = iMaxDiskSectors - iReservedSectors; + TUint32 calc2 = (256 * iSectorsPerCluster) + iNumberOfFats; + calc2 = calc2 >> 1; + return (calc1 + (calc2 - 1))/calc2; + } + + +const TUint KDefFatResvdSec = 1; ///< default number of FAT12/16 reserved sectors +const TUint KDefFat32ResvdSec = 32; ///< default number of FAT32 reserved sectors + +//------------------------------------------------------------------------------------------------------------------- +void Dump_TLDFormatInfo(const TLDFormatInfo& aInfo) +{ + (void)aInfo; +#ifdef _DEBUG + __PRINT(_L("----- TLDFormatInfo dump:")); + __PRINT1(_L("iCapacity:%d"), aInfo.iCapacity); + __PRINT1(_L("iSectorsPerCluster:%d"), aInfo.iSectorsPerCluster); + __PRINT1(_L("iSectorsPerTrack:%d"), aInfo.iSectorsPerTrack); + __PRINT1(_L("iFATBits:%d"), aInfo.iFATBits); + __PRINT1(_L("iReservedSectors:%d"), aInfo.iReservedSectors); + __PRINT1(_L("iFlags:%d"), aInfo.iFlags); + __PRINT(_L("-----")); +#endif +} + +//------------------------------------------------------------------------------------------------------------------- + +/** +Initialize the format parameters for a normal fixed sized disk +Setting set to adhere to Rules of Count of clusters for FAT type + +@param aDiskSizeInSectors Size of volume in sectors +@return system-wide error code +*/ +TInt CFatFormatCB::InitFormatDataForFixedSizeDiskNormal(TInt aDiskSizeInSectors, const TLocalDriveCapsV6& aCaps) + { + __PRINT1(_L("CFatFormatCB::InitFormatDataForFixedSizeDiskNormal() sectors:%d"), aDiskSizeInSectors); + + if( Drive().IsRemovable() ) + iNumberOfFats = KNumberOfFatsExternal; + else + iNumberOfFats = KNumberOfFatsInternal; + + iReservedSectors=KDefFatResvdSec; + if (aDiskSizeInSectors <=4084*1) // 2MB + { + iRootDirEntries=128; + iSectorsPerCluster=1; + iFileSystemName=KFileSystemName12; + iSectorsPerFat=MaxFat12Sectors(); + } + else if (aDiskSizeInSectors<4084*2) // < 4MB (8168 sectors) + { + iRootDirEntries=256; + iSectorsPerCluster=2; + iFileSystemName=KFileSystemName12; + iSectorsPerFat=MaxFat12Sectors(); + } + else if (aDiskSizeInSectors<4084*4) // < 8MB (16336 sectors) + { + iRootDirEntries=512; + iSectorsPerCluster=4; + iFileSystemName=KFileSystemName12; + iSectorsPerFat=MaxFat12Sectors(); + } + else if (aDiskSizeInSectors<4084*8) // < 16MB (32672 sectors) + { + iRootDirEntries=512; + iSectorsPerCluster=8; + iFileSystemName=KFileSystemName12; + iSectorsPerFat=MaxFat12Sectors(); + } + else if(aDiskSizeInSectors<1048576) // >= 16Mb - FAT16 < (1048576) 512MB + { + iFileSystemName=KFileSystemName16; + TInt minSectorsPerCluster=(aDiskSizeInSectors+KMaxFAT16Entries-1)/KMaxFAT16Entries; + iRootDirEntries=512; + iSectorsPerCluster=1; + while (minSectorsPerCluster>iSectorsPerCluster) + iSectorsPerCluster<<=1; + iSectorsPerFat=MaxFat16Sectors(); + } + else //use FAT32 + { + iFileSystemName=KFileSystemName32; + iRootDirEntries=0; //this is always the case for fat32 + if(aDiskSizeInSectors < 16777216) //8GB in 512byte sectors + iSectorsPerCluster=8; + else if(aDiskSizeInSectors < 33554432) //16GB in 512byte sectors + iSectorsPerCluster=16; + else if(aDiskSizeInSectors < 67108864) //32GB in 512byte sectors + iSectorsPerCluster=32; + else + iSectorsPerCluster=64; //Anything >= 32GB uses a 32K cluster size + iReservedSectors=KDefFat32ResvdSec; + iRootClusterNum=2; //As recomended in the document + iSectorsPerFat=MaxFat32Sectors(); + + } + + // Ensure cluster size is a multiple of the block size + TInt blockSizeInSectors = aCaps.iBlockSize >> iSectorSizeLog2; + __PRINT1(_L("blockSizeInSectors: %d"),blockSizeInSectors); + ASSERT(blockSizeInSectors == 0 || IsPowerOf2(blockSizeInSectors)); + if (blockSizeInSectors != 0 && IsPowerOf2(blockSizeInSectors)) + { + __PRINT1(_L("iSectorsPerCluster (old): %d"),iSectorsPerCluster); + AdjustClusterSize(blockSizeInSectors); + __PRINT1(_L("iSectorsPerCluster (new): %d"),iSectorsPerCluster); + } + + // Align first data sector on an erase block boundary if + // (1) the iEraseBlockSize is specified + // (2) the start of the partition is already aligned to an erase block boundary, + // i.e. iHiddenSectors is zero or a multiple of iEraseBlockSize + __PRINT1(_L("iHiddenSectors: %d"),iHiddenSectors); + TInt eraseblockSizeInSectors = aCaps.iEraseBlockSize >> iSectorSizeLog2; + __PRINT1(_L("eraseblockSizeInSectors: %d"),eraseblockSizeInSectors); + ASSERT(eraseblockSizeInSectors == 0 || IsPowerOf2(eraseblockSizeInSectors)); + ASSERT(eraseblockSizeInSectors == 0 || eraseblockSizeInSectors >= blockSizeInSectors); + if ((eraseblockSizeInSectors != 0) && + (iHiddenSectors % eraseblockSizeInSectors == 0) && + (IsPowerOf2(eraseblockSizeInSectors)) && + (eraseblockSizeInSectors >= blockSizeInSectors)) + { + TInt r = AdjustFirstDataSectorAlignment(eraseblockSizeInSectors); + ASSERT(r == KErrNone); + (void) r; + } + __PRINT1(_L("iReservedSectors: %d"),iReservedSectors); + __PRINT1(_L("FirstDataSector: %d"), FirstDataSector()); + + return KErrNone; + } + +TInt CFatFormatCB::FirstDataSector() const + { + TInt rootDirSectors = (iRootDirEntries * KSizeOfFatDirEntry + (iBytesPerSector-1)) / iBytesPerSector; + return iHiddenSectors + iReservedSectors + iNumberOfFats*iSectorsPerFat + rootDirSectors; + } + +void CFatFormatCB::AdjustClusterSize(TInt aRecommendedSectorsPerCluster) + { + const TInt KMaxSecPerCluster = 64; // 32K + while (aRecommendedSectorsPerCluster > iSectorsPerCluster && iSectorsPerCluster <= (KMaxSecPerCluster/2)) + iSectorsPerCluster<<= 1; + } + +// AdjustFirstDataSectorAlignment() +// Attempts to align the first data sector on an erase block boundary by modifying the +// number of reserved sectors. +TInt CFatFormatCB::AdjustFirstDataSectorAlignment(TInt aEraseBlockSizeInSectors) + { + const TBool bFat16 = Is16BitFat(); + const TBool bFat32 = Is32BitFat(); + + // Save these 2 values in the event of a convergence failure; this should + // hopefully never happen, but we will cater for this in release mode to be safe, + TInt reservedSectorsSaved = iReservedSectors; + TInt sectorsPerFatSaved = iSectorsPerFat; + + TInt reservedSectorsOld = 0; + + // zero for FAT32 + TInt rootDirSectors = (iRootDirEntries * KSizeOfFatDirEntry + (iBytesPerSector-1)) / iBytesPerSector; + TInt fatSectors = 0; + + TInt KMaxIterations = 10; + TInt n; + for (n=0; n= (TInt) (bFat32 ? KDefFat32ResvdSec : KDefFatResvdSec)); + + if ((FirstDataSector() & (aEraseBlockSizeInSectors-1)) == 0) + { + return KErrNone; + } + else + { + iReservedSectors = reservedSectorsSaved; + iSectorsPerFat = sectorsPerFatSaved; + return KErrGeneral; + } + } + + +//------------------------------------------------------------------------------------------------------------------- + +/** +Create the boot sector on media for the volume. For FAT32 also creates a backup copy of the boot sector. + +@leave System wide error codes +*/ +void CFatFormatCB::CreateBootSectorL() + { + __PRINT1(_L("CFatFormatCB::CreateBootSector() drive:%d"),DriveNumber()); + + + const TBool bFat32 = Is32BitFat(); + + TFatBootSector bootSector; + + bootSector.SetVendorID(KDefaultVendorID); + bootSector.SetBytesPerSector(iBytesPerSector); + bootSector.SetSectorsPerCluster(iSectorsPerCluster); + bootSector.SetReservedSectors(iReservedSectors); + bootSector.SetNumberOfFats(iNumberOfFats); + iCountOfClusters=iMaxDiskSectors/iSectorsPerCluster; + if (!bFat32) + { + if (iCountOfClusters>(TInt)KMaxTUint16) + User::Leave(KErrTooBig); + } + + bootSector.SetReservedByte(0); + TTime timeID; + timeID.HomeTime(); // System time in future? + bootSector.SetUniqueID(I64LOW(timeID.Int64())); // Generate UniqueID from time + bootSector.SetVolumeLabel(_L8("")); + bootSector.SetFileSysType(iFileSystemName); +// Floppy specific info: + bootSector.SetJumpInstruction(); + bootSector.SetMediaDescriptor(KBootSectorMediaDescriptor); + bootSector.SetNumberOfHeads(iNumberOfHeads); + bootSector.SetHiddenSectors(iHiddenSectors); + bootSector.SetSectorsPerTrack(iSectorsPerTrack); + bootSector.SetPhysicalDriveNumber(128); + bootSector.SetExtendedBootSignature(0x29); + + if(bFat32) + { + bootSector.SetFatSectors(0); + bootSector.SetFatSectors32(iSectorsPerFat); + bootSector.SetRootDirEntries(0); + bootSector.SetTotalSectors(0); + bootSector.SetHugeSectors(iMaxDiskSectors); + bootSector.SetFATFlags(0); + bootSector.SetVersionNumber(0x00); + bootSector.SetRootClusterNum(iRootClusterNum); + bootSector.SetFSInfoSectorNum(KFSInfoSectorNum); + bootSector.SetBkBootRecSector(KBkBootSectorNum); + } + else//fat12 and 16 + { + bootSector.SetFatSectors32(0); + bootSector.SetFatSectors(iSectorsPerFat); + bootSector.SetRootDirEntries(iRootDirEntries); + + if (iMaxDiskSectors<=(TInt)KMaxTUint16) + { + bootSector.SetTotalSectors(iMaxDiskSectors); + bootSector.SetHugeSectors(0); + } + else + { + bootSector.SetTotalSectors(0); + bootSector.SetHugeSectors(iMaxDiskSectors); + } + } + + //-- write main boot sector to the first sector on media + User::LeaveIfError(FatMount().DoWriteBootSector(KBootSectorNum*bootSector.BytesPerSector(), bootSector)); + + //-- for FAT32 write backup copy of the boot sector + if(bFat32) + { + User::LeaveIfError(FatMount().DoWriteBootSector(KBkBootSectorNum*bootSector.BytesPerSector(), bootSector)); + } + + } + +//------------------------------------------------------------------------------------------------------------------- + +/** +Format a disk section, called iteratively to erase whole of media, on last iteration +creates an empty volume. If called with quick formatonly erases the Fat leaving the +rest of the volume intact. + +@leave System wide error code +*/ +void CFatFormatCB::DoFormatStepL() + { + if (iFormatInfo.iFormatIsCurrent==EFalse) + { // Only done first time through + if (iMode & EForceErase) + { + TInt r = FatMount().ErasePassword(); + User::LeaveIfError(r); + // CFatMountCB::ErasePassword() calls TBusLocalDrive::ForceRemount(), + // so need to stop a remount from occurring in next call to : + // TFsFormatNext::DoRequestL((), TDrive::CheckMount(). + FatMount().Drive().SetChanged(EFalse); + } + + RecordOldInfoL(); + InitializeFormatDataL(); + FatMount().DoDismount(); + if (iVariableSize) + FatMount().ReduceSizeL(0,I64LOW(FatMount().iSize)); + } + // + // Blank disk if not EQuickFormat + // + if (!iVariableSize && !(iMode & EQuickFormat) && iCurrentStep) + { + if (iFormatInfo.iFormatIsCurrent == EFalse) + {//-- firstly invalidate sectors 0-6 inclusive, they may contain main boot sector, backup boot sector and FSInfo sector. + DoZeroFillMediaL(0, (KBkBootSectorNum+1)*iBytesPerSector); + } + TInt ret=FatMount().LocalDrive()->Format(iFormatInfo); + if (ret!=KErrNone && ret!=KErrEof) // Handle format error + ret = HandleCorrupt(ret); + + if (ret!=KErrNone && ret!=KErrEof) // KErrEof could be set by LocalDrive()->Format() + User::Leave(ret); + + if (ret==KErrNone) + { + iCurrentStep = I64LOW( 100 - (100 * TInt64(iFormatInfo.i512ByteSectorsFormatted)) / iMaxDiskSectors ); + if (iCurrentStep<=0) + iCurrentStep=1; + return; + } + } + + // ReMount since MBR may have been rewritten and partition may have moved / changed size + TInt ret = LocalDrive()->ForceRemount(0); + if (ret != KErrNone && ret != KErrNotSupported) + User::Leave(ret); + + // MBR may have changed, so need to re-read iHiddenSectors etc.before BPB is written + InitializeFormatDataL(); + + // Translate bad sector number to cluster number which contains that sector + // This only happens in full format, in quick format they are already cluster numbers + if (!iVariableSize && !(iMode & EQuickFormat)) + User::LeaveIfError(BadSectorToCluster()); + + //Check if root cluster is bad and update as required + if(Is32BitFat() && !iVariableSize && (iMode & EQuickFormat)) + { + if(iBadClusters.Find(iRootClusterNum) != KErrNotFound) + { + iRootClusterNum++; + while(iBadClusters.Find(iRootClusterNum) != KErrNotFound) + { + iRootClusterNum++; + } + } + } + + // + // Do the rest of the disk in one lump + // + iCurrentStep=0; + + //-- zero-fill media from position 0 to the FAT end, i.e main & backup boot sector, FSInfo and its copy and all FATs + const TUint32 posFatEnd = ((iSectorsPerFat*iNumberOfFats) + iReservedSectors) * iBytesPerSector; //-- last FAT end position + + if (iVariableSize) + FatMount().EnlargeL(posFatEnd); + + DoZeroFillMediaL(0, posFatEnd); + + if(Is32BitFat()) + {//create an empty root directory entry here + + const TUint KFat32EntrySz = 4; //-- FAT32 entry size, bytes + const TInt startFAT1 = iReservedSectors; //-- FAT1 start sector + const TInt entryOffset = iRootClusterNum*KFat32EntrySz; //-- Root dir entry offset in the FAT, bytes + + TBuf8 EOF(KFat32EntrySz); + EOF[0]=0xFF; + EOF[1]=0xFF; + EOF[2]=0xFF; + EOF[3]=0x0F; + + //-- write EOF mark to the every FAT copy + for(TInt i=0; iWrite(rootDirEntryPos, EOF)); + } + + //-- zero-fill FAT32 root directory (just 1 cluster) + const TInt firstDataSector = iReservedSectors + (iNumberOfFats * iSectorsPerFat); //+RootDirSectors (not required for fat32) + const TInt firstSectorOfCluster = ((iRootClusterNum - KFatFirstSearchCluster) * iSectorsPerCluster) + firstDataSector; + + const TUint32 posRootDirStart = firstSectorOfCluster * iBytesPerSector; + const TUint32 posRootDirEnd = posRootDirStart + iSectorsPerCluster*iBytesPerSector; + + DoZeroFillMediaL(posRootDirStart, posRootDirEnd); + } + else + {//-- FAT12/16 + //-- Zero fill root directory + const TInt rootDirSector = iReservedSectors + (iNumberOfFats * iSectorsPerFat); + const TInt rootDirSize = iRootDirEntries * KSizeOfFatDirEntry; //-- size in bytes + + const TUint32 posRootDirStart = rootDirSector * iBytesPerSector; + const TUint32 posRootDirEnd = posRootDirStart + rootDirSize; + + const TInt numOfRootSectors=(rootDirSize%iBytesPerSector) ? (rootDirSize/iBytesPerSector+1) : (rootDirSize/iBytesPerSector); + if (iVariableSize) + FatMount().EnlargeL(iBytesPerSector*numOfRootSectors); + + DoZeroFillMediaL(posRootDirStart, posRootDirEnd); + + // Enlarge ram drive to take into account rounding of + // data start to cluster boundary + if(iVariableSize && iSectorsPerCluster!=1) + { + const TInt firstFreeSector=rootDirSector+numOfRootSectors; + const TInt firstFreeCluster=firstFreeSector%iSectorsPerCluster ? firstFreeSector/iSectorsPerCluster+1 : firstFreeSector/iSectorsPerCluster; + const TInt alignedSector=firstFreeCluster*iSectorsPerCluster; + if(alignedSector!=firstFreeSector) + FatMount().EnlargeL((alignedSector-firstFreeSector)*iBytesPerSector); + } + } + + //-- FAT[0] must contain media descriptor in the low byte, FAT[1] for fat16/32 may contain some flags + TBuf8<8> startFat(8); + startFat.Fill(0xFF); + + if(Is32BitFat()) //-- FAT32 + {//-- FAT32 uses only low 28 bits in FAT entry. + startFat[3] = 0x0F; + startFat[7] = 0x0F; + } + else if(iVariableSize||Is16BitFat()) //-- FAT16 or RAM drive which is always FAT16 + { + startFat.SetLength(4); + } + else //-- FAT12 + { + startFat.SetLength(3); + } + + startFat[0]=KBootSectorMediaDescriptor; + + //-- write FAT[0] and FAT[1] entries to all copies of FAT + for(TInt i=0;iWrite(iBytesPerSector*(iReservedSectors+(iSectorsPerFat*i)),startFat)); + } + + //-- create boot sectors + CreateBootSectorL(); + + //-- create FSInfo sectors + if (Is32BitFat()) + { + CreateReservedBootSectorL(); + CreateFSInfoSectorL(); + } + + //-- here we have bad clusters numbers saved by the quick format + //-- Interpret old bad cluster number to new cluster number and mark new bad clusters + if (!iVariableSize && iBadClusters.Count()>0) + { + + //-- Here we need fully mounted volume, so mount it normally. + FatMount().MountL(EFalse); + + iBadClusters.Sort(); + TranslateL(); + const TInt mark = FatMount().Is32BitFat() ? KBad_32Bit : (FatMount().Is16BitFat() ? KBad_16Bit : KBad_12Bit); + + for (TInt i=0; iCaps(caps)); + iVariableSize=((caps().iMediaAtt)&KMediaAttVariableSize) ? (TBool)ETrue : (TBool)EFalse; + iDiskCorrupt = !FatMount().ConsistentState(); + iBadClusters.Reset(); + iBadSectors.Reset(); + if (!iVariableSize && !iDiskCorrupt && (iMode&EQuickFormat)) + { + iOldFirstFreeSector = FatMount().iFirstFreeByte>>FatMount().SectorSizeLog2(); + iOldSectorsPerCluster = FatMount().SectorsPerCluster(); + + FatMount().FAT().InvalidateCacheL(); //-- invalidate whole FAT cache + + // Collect bad cluster information from current FAT table + const TInt maxClusterNum = FatMount().UsableClusters() + KFatFirstSearchCluster; + const TUint32 mark = FatMount().Is32BitFat() ? KBad_32Bit : (FatMount().Is16BitFat() ? KBad_16Bit : KBad_12Bit); + + for (TInt i=KFatFirstSearchCluster; i>iSectorSizeLog2); + else + sizeofFatAndRootDir = (iRootClusterNum-2) * iSectorsPerCluster; + TInt firstFreeSector = iReservedSectors + sizeofFatAndRootDir; + + // Check in rare case that corrupt in critical area + // which includes bootsector, FAT table, (and root dir if not FAT32) + TInt i, r; + for (i=0; i badSector) + { + if (badSector == 0) // Boot sector corrupt + return KErrCorrupt; + if (iFileSystemName==KFileSystemName32 && badSector==1) // FSInfo corrupt + return KErrCorrupt; + if (badSector < iReservedSectors) // Harmless in reserved area + continue; + // Extend reserved area to cover bad sector + iReservedSectors = badSector + 1; + firstFreeSector = iReservedSectors + sizeofFatAndRootDir; + continue; + } + + // Figure out bad cluster number and record it + TUint cluster = (badSector-firstFreeSector)/iSectorsPerCluster+2; + if (iBadClusters.Find(cluster) == KErrNotFound) + { + if ((r=iBadClusters.Append(cluster)) != KErrNone) + return r; + if (iFileSystemName==KFileSystemName32 && iRootClusterNum==cluster) + iRootClusterNum++; + } + } + return KErrNone; + } + +/** +Create the File system information sector and its backup copy on a disk. +Note that CFatMountCB is still not in mounted state, so we can not rely on it. + +@leave System wide error codes +*/ +void CFatFormatCB::CreateFSInfoSectorL() + { + __PRINT1(_L("CFatFormatCB::CreateFSInfoSectorL() drv:%d"), DriveNumber()); + + ASSERT(Is32BitFat()); //-- Actually, CFatMount shall be in a consistent state. + + TFSInfo fsInfo; + TBuf8 fsInfoSecBuf; + + const TUint32 freeSectors = iMaxDiskSectors - (iReservedSectors + (iNumberOfFats * iSectorsPerFat)); + const TUint32 freeClusters = (freeSectors / iSectorsPerCluster) - 1; //-- 1st cluster is taken by empty Root Dir on FAT32 + const TUint32 nextFreeClust = iRootClusterNum+1; + + fsInfo.SetFreeClusterCount(freeClusters); + fsInfo.SetNextFreeCluster(nextFreeClust); + + fsInfo.Externalize(fsInfoSecBuf); //-- put data to the sector buffer + + User::LeaveIfError(LocalDrive()->Write(KFSInfoSectorNum*iBytesPerSector, fsInfoSecBuf)); //-- main FSInfo Sector + User::LeaveIfError(LocalDrive()->Write(KBkFSInfoSectorNum*iBytesPerSector, fsInfoSecBuf)); //-- Backup FSInfo Sector + + } + +/** +Create the reserved boot sector and its backup copy on a disk. +These are located at sectors 2 & 8 + +@leave System wide error codes +*/ +void CFatFormatCB::CreateReservedBootSectorL() + { + __PRINT1(_L("CFatFormatCB::CreateReserveBootSectorL() drv:%d"), DriveNumber()); + + ASSERT(Is32BitFat()); + + TFatBootSector bootSector; + + User::LeaveIfError(FatMount().DoWriteBootSector(KReservedBootSectorNum*KDefaultSectorSize, bootSector)); + User::LeaveIfError(FatMount().DoWriteBootSector(KBkReservedBootSectorNum*KDefaultSectorSize, bootSector)); + } + + + +