sl@0: // Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // f32\sfat\ram_fat_table.cpp sl@0: // FAT16 File Allocation Table classes implementation for the RAM media sl@0: // sl@0: // sl@0: sl@0: /** sl@0: @file sl@0: @internalTechnology sl@0: */ sl@0: sl@0: //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! sl@0: //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! sl@0: //!! sl@0: //!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it sl@0: //!! sl@0: //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! sl@0: //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! sl@0: sl@0: sl@0: #include "sl_std.h" sl@0: #include "sl_fatcache.h" sl@0: #include "fat_table.h" sl@0: sl@0: sl@0: //####################################################################################################################################### sl@0: //# CRamFatTable class implementation sl@0: //####################################################################################################################################### sl@0: sl@0: /** sl@0: Constructor, the RamFatTable allows disk compression by redirecting the FAT sl@0: sl@0: @param aOwner Owning mount. sl@0: */ sl@0: CRamFatTable::CRamFatTable(CFatMountCB& aOwner) sl@0: :CFatTable(aOwner) sl@0: { sl@0: iFatTablePos=aOwner.FirstFatSector()<InitializeL(); sl@0: CleanupStack::Pop(); sl@0: sl@0: return pSelf; sl@0: } sl@0: sl@0: void CRamFatTable::InitializeL() sl@0: { sl@0: CFatTable::InitializeL(); sl@0: sl@0: ASSERT(iMediaAtt & KMediaAttVariableSize); sl@0: sl@0: iFatTablePos=iOwner->FirstFatSector()<SectorSizeLog2(); sl@0: iIndirectionTablePos=iFatTablePos+iOwner->FatSizeInBytes(); sl@0: sl@0: //-- set RAM disk base sl@0: TLocalDriveCapsV2 caps; sl@0: TPckg capsPckg(caps); sl@0: User::LeaveIfError(iOwner->LocalDrive()->Caps(capsPckg)); sl@0: sl@0: iRamDiskBase = caps.iBaseAddress; sl@0: } sl@0: sl@0: /** sl@0: Remount the FAT table. This method call means that the media parameters wasn't changed, sl@0: otherwise CFatMountCB::DoReMountL() would reject it. sl@0: Just do some re-initialisation work. sl@0: */ sl@0: void CRamFatTable::ReMountL() sl@0: { sl@0: //-- re-initialise, actually sl@0: ASSERT(iMediaAtt & KMediaAttVariableSize); sl@0: ASSERT(FatType() == EFat16); sl@0: sl@0: iFatTablePos=iOwner->FirstFatSector()<SectorSizeLog2(); sl@0: iIndirectionTablePos=iFatTablePos+iOwner->FatSizeInBytes(); sl@0: sl@0: //-- set RAM disk base sl@0: TLocalDriveCapsV2 caps; sl@0: TPckg capsPckg(caps); sl@0: User::LeaveIfError(iOwner->LocalDrive()->Caps(capsPckg)); sl@0: sl@0: iRamDiskBase = caps.iBaseAddress; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Return the start address of the Ram Drive sl@0: sl@0: @return start address of the Ram Drive sl@0: */ sl@0: TUint8 *CRamFatTable::RamDiskBase() const sl@0: { sl@0: return(iRamDiskBase); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Allocate a new cluster number sl@0: sl@0: @return New cluster number sl@0: */ sl@0: TInt CRamFatTable::AllocateClusterNumber() sl@0: { sl@0: return(iOwner->MaxClusterNumber()-NumberOfFreeClusters()); sl@0: } sl@0: sl@0: /** sl@0: Write a value to the FAT (indirection table) sl@0: sl@0: @param aFatIndex Cluster to write to sl@0: @param aValue value to write to Fat sl@0: @leave sl@0: */ sl@0: void CRamFatTable::WriteL(TUint32 aFatIndex, TUint32 aValue) sl@0: { sl@0: //__PRINT(_L("CRamFatTable::WriteL")); sl@0: sl@0: __ASSERT_ALWAYS(aFatIndex>=2 && (aValue>=2 || aValue==0) && aValue<=0xFFFF,User::Leave(KErrCorrupt)); sl@0: TUint32 indirectCluster=aFatIndex; sl@0: TUint32 indirectClusterNewVal=0; sl@0: ReadIndirectionTable(indirectCluster); sl@0: // If value in indirection table!=0 we assume we have already written to the indirection table sl@0: // So just update the FAT table sl@0: if (indirectCluster!=0 && aValue!=0) sl@0: { sl@0: WriteFatTable(aFatIndex,aValue); sl@0: return; sl@0: } sl@0: // If value in indirection table is 0, we haven't written to it yet, though the memory has sl@0: // already been allocated by the EnlargeL() function sl@0: if (indirectCluster==0 && aValue!=0) // Assumes memory has already been allocated sl@0: indirectClusterNewVal=AllocateClusterNumber(); sl@0: // Write aValue into aFaxIndex and indirectClusterNewVal into the corresponding position sl@0: // in the indirection table sl@0: WriteFatTable(aFatIndex,aValue,indirectClusterNewVal); sl@0: } sl@0: sl@0: /** sl@0: Read the value of a cluster in the Fat sl@0: sl@0: @param aFatIndex A cluster to read sl@0: @leave sl@0: @return The cluster value read sl@0: */ sl@0: sl@0: TUint32 CRamFatTable::ReadL(TUint32 aFatIndex) const sl@0: { sl@0: __ASSERT_ALWAYS(aFatIndex>=KFatFirstSearchCluster,User::Leave(KErrCorrupt)); sl@0: TUint clusterVal=*(TUint16*)(RamDiskBase()+PosInBytes(aFatIndex)+iFatTablePos); sl@0: return(clusterVal); sl@0: } sl@0: sl@0: /** sl@0: Write a value to the FAT and indirection table sl@0: sl@0: @param aFatIndex Cluster number to write to sl@0: @param aFatValue Cluster value for Fat sl@0: @param anIndirectionValue Value for indirection table sl@0: */ sl@0: void CRamFatTable::WriteFatTable(TInt aFatIndex,TInt aFatValue,TInt anIndirectionValue) sl@0: { sl@0: TUint8* pos=RamDiskBase()+PosInBytes(aFatIndex); sl@0: *(TUint16*)(pos+iFatTablePos)=(TUint16)aFatValue; sl@0: *(TUint16*)(pos+iIndirectionTablePos)=(TUint16)anIndirectionValue; sl@0: } sl@0: sl@0: /** sl@0: Write to just the fat table sl@0: sl@0: @param aFatIndex Cluster number to write to sl@0: @param aFatValue Cluster value for Fat sl@0: */ sl@0: void CRamFatTable::WriteFatTable(TInt aFatIndex,TInt aFatValue) sl@0: { sl@0: *(TUint16*)(RamDiskBase()+PosInBytes(aFatIndex)+iFatTablePos)=(TUint16)aFatValue; sl@0: } sl@0: sl@0: /** sl@0: Write to just the fat table sl@0: sl@0: @param aFatIndex Cluster number to write to sl@0: @param aFatValue Value for indirection table sl@0: */ sl@0: void CRamFatTable::WriteIndirectionTable(TInt aFatIndex,TInt aFatValue) sl@0: { sl@0: *(TUint16*)(RamDiskBase()+PosInBytes(aFatIndex)+iIndirectionTablePos)=(TUint16)aFatValue; sl@0: } sl@0: sl@0: /** sl@0: Find the real location of aCluster sl@0: sl@0: @param aCluster Cluster to read, contians cluster value upon return sl@0: */ sl@0: void CRamFatTable::ReadIndirectionTable(TUint32& aCluster) const sl@0: { sl@0: aCluster=*(TUint16*)(RamDiskBase()+PosInBytes(aCluster)+iIndirectionTablePos); sl@0: } sl@0: sl@0: /** sl@0: Copy memory in RAM drive area, unlocking required sl@0: sl@0: @param aTrg Pointer to destination location sl@0: @param aSrc Pointer to source location sl@0: @param aLength Length of data to copy sl@0: @return Pointer to end of data copied sl@0: */ sl@0: TUint8* CRamFatTable::MemCopy(TAny* aTrg,const TAny* aSrc,TInt aLength) sl@0: { sl@0: TUint8* p=Mem::Copy(aTrg,aSrc,aLength); sl@0: return(p); sl@0: } sl@0: sl@0: /** sl@0: Copy memory with filling the source buffer with zeroes. Target and source buffers can overlap. sl@0: Used on RAMDrive srinking in order to wipe data from the file that is being deleted. sl@0: sl@0: @param aTrg pointer to the target address sl@0: @param aSrc pointer to the destination address sl@0: @param aLength how many bytes to copy sl@0: @return A pointer to a location aLength bytes beyond aTrg (i.e. the location aTrg+aLength). sl@0: */ sl@0: TUint8* CRamFatTable::MemCopyFillZ(TAny* aTrg, TAny* aSrc,TInt aLength) sl@0: { sl@0: //-- just copy src to the trg, the memory areas can overlap. sl@0: TUint8* p=Mem::Copy(aTrg, aSrc, aLength); sl@0: sl@0: //-- now zero-fill the source memory area taking into account possible overlap. sl@0: TUint8* pSrc = static_cast(aSrc); sl@0: TUint8* pTrg = static_cast(aTrg); sl@0: sl@0: TUint8* pZFill = NULL; //-- pointer to the beginning of zerofilled area sl@0: TInt zFillLen = 0; //-- a number of bytes to zero-fill sl@0: sl@0: if(aTrg < aSrc) sl@0: { sl@0: if(pTrg+aLength < pSrc) sl@0: {//-- target and source areas do not overlap sl@0: pZFill = pSrc; sl@0: zFillLen = aLength; sl@0: } sl@0: else sl@0: {//-- target and source areas overlap, try not to corrupt the target area sl@0: zFillLen = pSrc-pTrg; sl@0: pZFill = pTrg+aLength; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: if(pSrc+aLength < pTrg) sl@0: {//-- target and source areas do not overlap sl@0: pZFill = pSrc; sl@0: zFillLen = aLength; sl@0: } sl@0: else sl@0: {//-- target and source areas overlap, try not to corrupt the target area sl@0: zFillLen = pSrc+aLength-pTrg; sl@0: pZFill = pSrc; sl@0: } sl@0: } sl@0: sl@0: Mem::FillZ(pZFill, zFillLen); sl@0: sl@0: return(p); sl@0: } sl@0: sl@0: /** sl@0: Zero fill RAM area corresponding to the cluster number aCluster sl@0: @param aCluster a cluster number to be zero-filled sl@0: */ sl@0: void CRamFatTable::ZeroFillCluster(TInt aCluster) sl@0: { sl@0: TLinAddr clusterPos= I64LOW(DataPositionInBytes(aCluster)); sl@0: Mem::FillZ(iRamDiskBase+clusterPos, 1<< iOwner->ClusterSizeLog2()); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Return the location of a Cluster in the data section of the media sl@0: sl@0: @param aCluster to find location of sl@0: @return Byte offset of the cluster data sl@0: */ sl@0: TInt64 CRamFatTable::DataPositionInBytes(TUint32 aCluster) const sl@0: { sl@0: //__PRINT(_L("CRamFatTable::DataPositionInBytes")); sl@0: ReadIndirectionTable(aCluster); sl@0: return(aCluster<ClusterSizeLog2()); sl@0: } sl@0: sl@0: /** sl@0: Allocate and mark as EOF a single cluster as close as possible to aNearestCluster, sl@0: calls base class implementation but must Enlarge the RAM drive first. Allocated cluster RAM area will be zero-filled. sl@0: sl@0: @param aNearestCluster Cluster the new cluster should be nearest to sl@0: @leave System wide error codes sl@0: @return The cluster number allocated sl@0: */ sl@0: TUint32 CRamFatTable::AllocateSingleClusterL(TUint32 aNearestCluster) sl@0: { sl@0: __PRINT(_L("CRamFatTable::AllocateSingleClusterL")); sl@0: iOwner->EnlargeL(1<ClusterSizeLog2()); // First enlarge the RAM drive sl@0: TInt fileAllocated=CFatTable::AllocateSingleClusterL(aNearestCluster); // Now update the free cluster and fat/fit sl@0: ZeroFillCluster(fileAllocated); //-- zero-fill allocated cluster sl@0: return(fileAllocated); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Extend a file or directory cluster chain, enlarging RAM drive first. Allocated clusters are zero-filled. sl@0: Leaves if there are no free clusters (the disk is full). sl@0: Note that method now doesn't call CFatTable::ExtendClusterListL() from its base class, be careful making changes there. sl@0: sl@0: @param aNumber number of clusters to allocate sl@0: @param aCluster starting cluster number / ending cluster number after sl@0: @leave KErrDiskFull + system wide error codes sl@0: */ sl@0: void CRamFatTable::ExtendClusterListL(TUint32 aNumber,TInt& aCluster) sl@0: { sl@0: __PRINT(_L("CRamFatTable::ExtendClusterListL")); sl@0: __ASSERT_DEBUG(aNumber>0,Fault(EFatBadParameter)); sl@0: sl@0: iOwner->EnlargeL(aNumber<ClusterSizeLog2()); sl@0: sl@0: while(aNumber && GetNextClusterL(aCluster)) sl@0: aNumber--; sl@0: sl@0: if(!aNumber) sl@0: return; sl@0: sl@0: if (NumberOfFreeClusters() < aNumber) sl@0: { sl@0: __PRINT(_L("CRamFatTable::ExtendClusterListL - leaving KErrDirFull")); sl@0: User::Leave(KErrDiskFull); sl@0: } sl@0: sl@0: while (aNumber--) sl@0: { sl@0: const TInt freeCluster=FindClosestFreeClusterL(aCluster); sl@0: sl@0: WriteFatEntryEofL(freeCluster); // Must write EOF for FindClosestFreeCluster to work again sl@0: DecrementFreeClusterCount(1); sl@0: WriteL(aCluster,freeCluster); sl@0: aCluster=freeCluster; sl@0: ZeroFillCluster(freeCluster); //-- zero fill just allocated cluster (RAM area) sl@0: } sl@0: sl@0: SetFreeClusterHint(aCluster); sl@0: sl@0: } sl@0: sl@0: /** sl@0: Mark a chain of clusters as free in the FAT. Shrinks the RAM drive once the sl@0: clusters are free sl@0: sl@0: @param aCluster Start cluster of cluster chain to free sl@0: @leave System wide error codes sl@0: */ sl@0: void CRamFatTable::FreeClusterListL(TUint32 aCluster) sl@0: { sl@0: __PRINT1(_L("CRamFatTable::FreeClusterListL aCluster=%d"),aCluster); sl@0: if (aCluster==0) sl@0: return; // File has no cluster allocated sl@0: sl@0: const TInt clusterShift=iOwner->ClusterSizeLog2(); sl@0: TInt startCluster=aCluster; sl@0: TInt endCluster=0; sl@0: TInt totalFreed=0; sl@0: TLinAddr srcEnd=0; sl@0: sl@0: while(endCluster!=EOF_16Bit) sl@0: { sl@0: TInt num=CountContiguousClustersL(startCluster,endCluster,KMaxTInt); sl@0: if (GetNextClusterL(endCluster)==EFalse || endCluster==0) sl@0: endCluster=EOF_16Bit; // endCluster==0 -> file contained FAT loop sl@0: sl@0: // Real position in bytes of the start cluster in the data area sl@0: TLinAddr startClusterPos= I64LOW(DataPositionInBytes(startCluster)); sl@0: // Sliding value when more than one block is freed sl@0: TLinAddr trg=startClusterPos-(totalFreed<Size()); sl@0: __PRINT1(_L("srcEnd=0x%x"),srcEnd); sl@0: } sl@0: else // Just move up to the next part of the chain sl@0: srcEnd=I64LOW(DataPositionInBytes(endCluster)); sl@0: sl@0: //-- Copy (srcEnd-srcStart) bytes from iRamDiskBase+srcStart onto iRamDiskBase+trg sl@0: //-- zero-filling free space to avoid leaving something important there sl@0: ASSERT(srcEnd >= srcStart); sl@0: if(srcEnd-srcStart > 0) sl@0: { sl@0: MemCopyFillZ(iRamDiskBase+trg,iRamDiskBase+srcStart,srcEnd-srcStart); sl@0: } sl@0: else sl@0: {//-- we are freeing the cluster chain at the end of the RAMdrive; Nothing to copy to the drive space that has become free, sl@0: //-- but nevertheless zero fill this space. sl@0: Mem::FillZ(iRamDiskBase+trg, num<>clusterShift,srcEnd>>clusterShift,totalFreed); sl@0: } sl@0: TInt bytesFreed=totalFreed<ReduceSizeL(srcEnd-bytesFreed,bytesFreed); sl@0: } sl@0: sl@0: /** sl@0: Shift any clusters between aStart and anEnd backwards by aClusterShift sl@0: sl@0: @param aStart Start of shift region sl@0: @param anEnd End of shift region sl@0: @param aClusterShift amount to shift cluster by sl@0: */ sl@0: void CRamFatTable::UpdateIndirectionTable(TUint32 aStart,TUint32 anEnd,TInt aClusterShift) sl@0: { sl@0: __PRINT(_L("CRamFatTable::UpdateIndirectionTable")); sl@0: #if defined(__WINS__) sl@0: TUint32 count=iOwner->MaxClusterNumber(); sl@0: while (count--) sl@0: { sl@0: TUint32 cluster=count; sl@0: ReadIndirectionTable(cluster); sl@0: if (cluster>=aStart && clusterMaxClusterNumber(); sl@0: while (entry>table) sl@0: { sl@0: TUint32 cluster=*--entry; sl@0: if (cluster