diff -r 000000000000 -r 96e5fb8b040d userlibandfileserver/fileserver/sfat/sl_fat16.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/userlibandfileserver/fileserver/sfat/sl_fat16.cpp Thu Dec 17 09:24:54 2009 +0200 @@ -0,0 +1,629 @@ +// 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_fat16.cpp +// +// +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +//!! +//!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it +//!! +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + +#include "sl_std.h" +#include "sl_cache.h" + +const TUint KDefFatResvdSec = 1; ///< default number of FAT12/16 reserved sectors + +/** +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) + { + 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 // >= 16Mb - FAT16 + { + iFileSystemName=KFileSystemName16; + TInt minSectorsPerCluster=(aDiskSizeInSectors+KMaxFAT16Entries-1)/KMaxFAT16Entries; + iRootDirEntries=512; + iSectorsPerCluster=1; + while (minSectorsPerCluster>iSectorsPerCluster) + iSectorsPerCluster<<=1; + iSectorsPerFat=MaxFat16Sectors(); + } + + // 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(); + + // 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) KDefFatResvdSec); + + if ((FirstDataSector() & (aEraseBlockSizeInSectors-1)) == 0) + { + return KErrNone; + } + else + { + iReservedSectors = reservedSectorsSaved; + iSectorsPerFat = sectorsPerFatSaved; + return KErrGeneral; + } + } + +/** + Initialize the user specific format parameters for fixed sized disk. + + @param aDiskSizeInSectors disk size in sectors + @return system-wide error code +*/ +TInt CFatFormatCB::InitFormatDataForFixedSizeDiskUser(TInt aDiskSizeInSectors) + { + //-- KErrArgument will be returned if iSpecialInfo().iFATBits isn't one of EFB32, EFB16, EFB32 + + if(iSpecialInfo().iFlags & TLDFormatInfo::EOneFatTable) + iNumberOfFats = 1; + else if(iSpecialInfo().iFlags & TLDFormatInfo::ETwoFatTables) + iNumberOfFats = 2; + else if(Drive().IsRemovable()) + iNumberOfFats = KNumberOfFatsExternal; + else + iNumberOfFats = KNumberOfFatsInternal; + + + if(iSpecialInfo().iReservedSectors == 0) + iReservedSectors = KDefFatResvdSec; //-- user hasn't specified reserved sectors count, use default (FAT12/16) + else + iReservedSectors = iSpecialInfo().iReservedSectors; + + + const TInt KMaxSecPerCluster = 64; + const TInt KDefaultSecPerCluster= 8; //-- default value, if the iSpecialInfo().iSectorsPerCluster isn't specified + + iSectorsPerCluster = iSpecialInfo().iSectorsPerCluster; + if(iSectorsPerCluster <= 0) + {//-- default value, user hasn't specified TLDFormatInfo::iSectorsPerCluster + iSectorsPerCluster = KDefaultSecPerCluster; //-- will be adjusted later + } + else + { + iSectorsPerCluster = Min(1<= 64Mb + iRootDirEntries = 512; + + //----------------------------------------- + + TLDFormatInfo::TFATBits fatBits = iSpecialInfo().iFATBits; + if (fatBits == TLDFormatInfo::EFBDontCare) + { + const TFatType fatType = SuggestFatType(); + switch(fatType) + { + case EFat12: + fatBits = TLDFormatInfo::EFB12; + break; + case EFat16: + fatBits = TLDFormatInfo::EFB16; + break; + case EFat32: + fatBits = TLDFormatInfo::EFB32; + break; + case EInvalid: + ASSERT(0); + } + } + + TFatType reqFatType(EInvalid); //-- requested FAT type + + switch (fatBits) + { + case TLDFormatInfo::EFB12: + iFileSystemName=KFileSystemName12; + iSectorsPerFat=MaxFat12Sectors(); + reqFatType = EFat12; + break; + + case TLDFormatInfo::EFB16: + iFileSystemName=KFileSystemName16; + iSectorsPerFat=MaxFat16Sectors(); + reqFatType = EFat16; + break; + + case TLDFormatInfo::EFB32: + __PRINT(_L("CFatFormatCB::InitFormatDataForFixedSizeDiskUser() FAT32 Not supported!")); + return KErrNotSupported; + + default: + __PRINT(_L("CFatFormatCB::InitFormatDataForFixedSizeDiskUser() Incorrect FAT type specifier!")); + return KErrArgument; + }; + + //-- check if we can format the volume with requested FAT type + const TFatType fatType = SuggestFatType(); + if(fatType != reqFatType) + {//-- volume metrics don't correspond to the requested FAT type + __PRINT(_L("CFatFormatCB::InitFormatDataForFixedSizeDiskUser() FAT type mismatch!")); + return KErrArgument; + } + + + return KErrNone; + } + +/** + Initialize the format parameters for a custom fixed sized disk + + @param aFormatInfo The custom format parameters + @return system-wide error code +*/ +TInt CFatFormatCB::InitFormatDataForFixedSizeDiskCustom(const TLDFormatInfo& aFormatInfo) + { + if(aFormatInfo.iFlags & TLDFormatInfo::EOneFatTable) + iNumberOfFats = 1; + else if(aFormatInfo.iFlags & TLDFormatInfo::ETwoFatTables) + iNumberOfFats = 2; + else if(Drive().IsRemovable()) + iNumberOfFats = KNumberOfFatsExternal; + else + iNumberOfFats = KNumberOfFatsInternal; + + iRootDirEntries=512; + + iSectorsPerCluster = aFormatInfo.iSectorsPerCluster; + iSectorsPerTrack = aFormatInfo.iSectorsPerTrack; + iNumberOfHeads = aFormatInfo.iNumberOfSides; + iReservedSectors = aFormatInfo.iReservedSectors ? aFormatInfo.iReservedSectors : KDefFatResvdSec; + + switch (aFormatInfo.iFATBits) + { + case TLDFormatInfo::EFB12: + iFileSystemName = KFileSystemName12; + iSectorsPerFat = MaxFat12Sectors(); + break; + + case TLDFormatInfo::EFB16: + iFileSystemName = KFileSystemName16; + iSectorsPerFat = MaxFat16Sectors(); + break; + + default: + { + TInt64 clusters64 = (aFormatInfo.iCapacity / KDefaultSectorSize) / iSectorsPerCluster; + TInt clusters = I64LOW(clusters64); + if (clusters < 4085) + { + iFileSystemName = KFileSystemName12; + iSectorsPerFat = MaxFat12Sectors(); + } + else + { + iFileSystemName = KFileSystemName16; + iSectorsPerFat = MaxFat16Sectors(); + } + } + } + + return KErrNone; + } + +void CFatFormatCB::RecordOldInfoL() + { + __PRINT(_L("CFatFormatCB::RecordOldInfoL")); + // Check if mount or disk is corrupt + // This should be stored in member variable because FatMount is remounted + // every time RFormat::Next() gets called thus FatMount().Initialised() + // will be inconsistent with previous state. + TLocalDriveCapsV3Buf caps; + User::LeaveIfError(LocalDrive()->Caps(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 + + const TInt maxClusterNum = FatMount().iUsableClusters + KFatFirstSearchCluster; + + // Collect bad cluster information from current FAT table + const TUint32 mark = FatMount().Is16BitFat() ? KBad_16Bit : KBad_12Bit; + for (TInt i=KFatFirstSearchCluster; i(TInt)KMaxTUint16) + User::Leave(KErrTooBig); + bootSector.SetFatSectors(iSectorsPerFat); + 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); + + + User::LeaveIfError(FatMount().DoWriteBootSector(KBootSectorNum*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) + { + 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 + DoZeroFillMediaL(0, 7*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=100-(100*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()); + + // + // 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); + + //-- 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<4> startFat(4); + startFat.Fill(0xFF); + + 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(); + + //-- 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(); + TInt mark = FatMount().Is16BitFat() ? KBad_16Bit : KBad_12Bit; + TInt i; + + for (i=0; i>iSectorSizeLog2); + TInt firstFreeSector = iReservedSectors + sizeofFatAndRootDir; + + TInt i, r; + for (i=0; i