1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/userlibandfileserver/fileserver/sfat/ram_fat_table.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,485 @@
1.4 +// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// f32\sfat\ram_fat_table.cpp
1.18 +// FAT16 File Allocation Table classes implementation for the RAM media
1.19 +//
1.20 +//
1.21 +
1.22 +/**
1.23 + @file
1.24 + @internalTechnology
1.25 +*/
1.26 +
1.27 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1.28 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1.29 +//!!
1.30 +//!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it
1.31 +//!!
1.32 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1.33 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1.34 +
1.35 +
1.36 +#include "sl_std.h"
1.37 +#include "sl_fatcache.h"
1.38 +#include "fat_table.h"
1.39 +
1.40 +
1.41 +//#######################################################################################################################################
1.42 +//# CRamFatTable class implementation
1.43 +//#######################################################################################################################################
1.44 +
1.45 +/**
1.46 +Constructor, the RamFatTable allows disk compression by redirecting the FAT
1.47 +
1.48 +@param aOwner Owning mount.
1.49 +*/
1.50 +CRamFatTable::CRamFatTable(CFatMountCB& aOwner)
1.51 + :CFatTable(aOwner)
1.52 + {
1.53 + iFatTablePos=aOwner.FirstFatSector()<<aOwner.SectorSizeLog2();
1.54 + iIndirectionTablePos=iFatTablePos+aOwner.FatSizeInBytes();
1.55 + }
1.56 +
1.57 +/** factory method */
1.58 +CRamFatTable* CRamFatTable::NewL(CFatMountCB& aOwner)
1.59 +{
1.60 + __PRINT1(_L("CRamFatTable::NewL() drv:%d"),aOwner.DriveNumber());
1.61 +
1.62 + CRamFatTable* pSelf = new (ELeave) CRamFatTable(aOwner);
1.63 +
1.64 + CleanupStack::PushL(pSelf);
1.65 + pSelf->InitializeL();
1.66 + CleanupStack::Pop();
1.67 +
1.68 + return pSelf;
1.69 +}
1.70 +
1.71 +void CRamFatTable::InitializeL()
1.72 +{
1.73 + CFatTable::InitializeL();
1.74 +
1.75 + ASSERT(iMediaAtt & KMediaAttVariableSize);
1.76 +
1.77 + iFatTablePos=iOwner->FirstFatSector()<<iOwner->SectorSizeLog2();
1.78 + iIndirectionTablePos=iFatTablePos+iOwner->FatSizeInBytes();
1.79 +
1.80 + //-- set RAM disk base
1.81 + TLocalDriveCapsV2 caps;
1.82 + TPckg<TLocalDriveCapsV2> capsPckg(caps);
1.83 + User::LeaveIfError(iOwner->LocalDrive()->Caps(capsPckg));
1.84 +
1.85 + iRamDiskBase = caps.iBaseAddress;
1.86 +}
1.87 +
1.88 +/**
1.89 + Remount the FAT table. This method call means that the media parameters wasn't changed,
1.90 + otherwise CFatMountCB::DoReMountL() would reject it.
1.91 + Just do some re-initialisation work.
1.92 +*/
1.93 +void CRamFatTable::ReMountL()
1.94 +{
1.95 + //-- re-initialise, actually
1.96 + ASSERT(iMediaAtt & KMediaAttVariableSize);
1.97 + ASSERT(FatType() == EFat16);
1.98 +
1.99 + iFatTablePos=iOwner->FirstFatSector()<<iOwner->SectorSizeLog2();
1.100 + iIndirectionTablePos=iFatTablePos+iOwner->FatSizeInBytes();
1.101 +
1.102 + //-- set RAM disk base
1.103 + TLocalDriveCapsV2 caps;
1.104 + TPckg<TLocalDriveCapsV2> capsPckg(caps);
1.105 + User::LeaveIfError(iOwner->LocalDrive()->Caps(capsPckg));
1.106 +
1.107 + iRamDiskBase = caps.iBaseAddress;
1.108 +}
1.109 +
1.110 +
1.111 +/**
1.112 +Return the start address of the Ram Drive
1.113 +
1.114 +@return start address of the Ram Drive
1.115 +*/
1.116 +TUint8 *CRamFatTable::RamDiskBase() const
1.117 + {
1.118 + return(iRamDiskBase);
1.119 + }
1.120 +
1.121 +
1.122 +/**
1.123 +Allocate a new cluster number
1.124 +
1.125 +@return New cluster number
1.126 +*/
1.127 +TInt CRamFatTable::AllocateClusterNumber()
1.128 + {
1.129 + return(iOwner->MaxClusterNumber()-NumberOfFreeClusters());
1.130 + }
1.131 +
1.132 +/**
1.133 +Write a value to the FAT (indirection table)
1.134 +
1.135 +@param aFatIndex Cluster to write to
1.136 +@param aValue value to write to Fat
1.137 +@leave
1.138 +*/
1.139 +void CRamFatTable::WriteL(TUint32 aFatIndex, TUint32 aValue)
1.140 + {
1.141 + //__PRINT(_L("CRamFatTable::WriteL"));
1.142 +
1.143 + __ASSERT_ALWAYS(aFatIndex>=2 && (aValue>=2 || aValue==0) && aValue<=0xFFFF,User::Leave(KErrCorrupt));
1.144 + TUint32 indirectCluster=aFatIndex;
1.145 + TUint32 indirectClusterNewVal=0;
1.146 + ReadIndirectionTable(indirectCluster);
1.147 +// If value in indirection table!=0 we assume we have already written to the indirection table
1.148 +// So just update the FAT table
1.149 + if (indirectCluster!=0 && aValue!=0)
1.150 + {
1.151 + WriteFatTable(aFatIndex,aValue);
1.152 + return;
1.153 + }
1.154 +// If value in indirection table is 0, we haven't written to it yet, though the memory has
1.155 +// already been allocated by the EnlargeL() function
1.156 + if (indirectCluster==0 && aValue!=0) // Assumes memory has already been allocated
1.157 + indirectClusterNewVal=AllocateClusterNumber();
1.158 +// Write aValue into aFaxIndex and indirectClusterNewVal into the corresponding position
1.159 +// in the indirection table
1.160 + WriteFatTable(aFatIndex,aValue,indirectClusterNewVal);
1.161 + }
1.162 +
1.163 +/**
1.164 +Read the value of a cluster in the Fat
1.165 +
1.166 +@param aFatIndex A cluster to read
1.167 +@leave
1.168 +@return The cluster value read
1.169 +*/
1.170 +
1.171 +TUint32 CRamFatTable::ReadL(TUint32 aFatIndex) const
1.172 + {
1.173 + __ASSERT_ALWAYS(aFatIndex>=KFatFirstSearchCluster,User::Leave(KErrCorrupt));
1.174 + TUint clusterVal=*(TUint16*)(RamDiskBase()+PosInBytes(aFatIndex)+iFatTablePos);
1.175 + return(clusterVal);
1.176 + }
1.177 +
1.178 +/**
1.179 +Write a value to the FAT and indirection table
1.180 +
1.181 +@param aFatIndex Cluster number to write to
1.182 +@param aFatValue Cluster value for Fat
1.183 +@param anIndirectionValue Value for indirection table
1.184 +*/
1.185 +void CRamFatTable::WriteFatTable(TInt aFatIndex,TInt aFatValue,TInt anIndirectionValue)
1.186 + {
1.187 + TUint8* pos=RamDiskBase()+PosInBytes(aFatIndex);
1.188 + *(TUint16*)(pos+iFatTablePos)=(TUint16)aFatValue;
1.189 + *(TUint16*)(pos+iIndirectionTablePos)=(TUint16)anIndirectionValue;
1.190 + }
1.191 +
1.192 +/**
1.193 +Write to just the fat table
1.194 +
1.195 +@param aFatIndex Cluster number to write to
1.196 +@param aFatValue Cluster value for Fat
1.197 +*/
1.198 +void CRamFatTable::WriteFatTable(TInt aFatIndex,TInt aFatValue)
1.199 + {
1.200 + *(TUint16*)(RamDiskBase()+PosInBytes(aFatIndex)+iFatTablePos)=(TUint16)aFatValue;
1.201 + }
1.202 +
1.203 +/**
1.204 +Write to just the fat table
1.205 +
1.206 +@param aFatIndex Cluster number to write to
1.207 +@param aFatValue Value for indirection table
1.208 +*/
1.209 +void CRamFatTable::WriteIndirectionTable(TInt aFatIndex,TInt aFatValue)
1.210 + {
1.211 + *(TUint16*)(RamDiskBase()+PosInBytes(aFatIndex)+iIndirectionTablePos)=(TUint16)aFatValue;
1.212 + }
1.213 +
1.214 +/**
1.215 +Find the real location of aCluster
1.216 +
1.217 +@param aCluster Cluster to read, contians cluster value upon return
1.218 +*/
1.219 +void CRamFatTable::ReadIndirectionTable(TUint32& aCluster) const
1.220 + {
1.221 + aCluster=*(TUint16*)(RamDiskBase()+PosInBytes(aCluster)+iIndirectionTablePos);
1.222 + }
1.223 +
1.224 +/**
1.225 +Copy memory in RAM drive area, unlocking required
1.226 +
1.227 +@param aTrg Pointer to destination location
1.228 +@param aSrc Pointer to source location
1.229 +@param aLength Length of data to copy
1.230 +@return Pointer to end of data copied
1.231 +*/
1.232 +TUint8* CRamFatTable::MemCopy(TAny* aTrg,const TAny* aSrc,TInt aLength)
1.233 + {
1.234 + TUint8* p=Mem::Copy(aTrg,aSrc,aLength);
1.235 + return(p);
1.236 + }
1.237 +
1.238 +/**
1.239 + Copy memory with filling the source buffer with zeroes. Target and source buffers can overlap.
1.240 + Used on RAMDrive srinking in order to wipe data from the file that is being deleted.
1.241 +
1.242 + @param aTrg pointer to the target address
1.243 + @param aSrc pointer to the destination address
1.244 + @param aLength how many bytes to copy
1.245 + @return A pointer to a location aLength bytes beyond aTrg (i.e. the location aTrg+aLength).
1.246 +*/
1.247 +TUint8* CRamFatTable::MemCopyFillZ(TAny* aTrg, TAny* aSrc,TInt aLength)
1.248 +{
1.249 + //-- just copy src to the trg, the memory areas can overlap.
1.250 + TUint8* p=Mem::Copy(aTrg, aSrc, aLength);
1.251 +
1.252 + //-- now zero-fill the source memory area taking into account possible overlap.
1.253 + TUint8* pSrc = static_cast<TUint8*>(aSrc);
1.254 + TUint8* pTrg = static_cast<TUint8*>(aTrg);
1.255 +
1.256 + TUint8* pZFill = NULL; //-- pointer to the beginning of zerofilled area
1.257 + TInt zFillLen = 0; //-- a number of bytes to zero-fill
1.258 +
1.259 + if(aTrg < aSrc)
1.260 + {
1.261 + if(pTrg+aLength < pSrc)
1.262 + {//-- target and source areas do not overlap
1.263 + pZFill = pSrc;
1.264 + zFillLen = aLength;
1.265 + }
1.266 + else
1.267 + {//-- target and source areas overlap, try not to corrupt the target area
1.268 + zFillLen = pSrc-pTrg;
1.269 + pZFill = pTrg+aLength;
1.270 + }
1.271 + }
1.272 + else
1.273 + {
1.274 + if(pSrc+aLength < pTrg)
1.275 + {//-- target and source areas do not overlap
1.276 + pZFill = pSrc;
1.277 + zFillLen = aLength;
1.278 + }
1.279 + else
1.280 + {//-- target and source areas overlap, try not to corrupt the target area
1.281 + zFillLen = pSrc+aLength-pTrg;
1.282 + pZFill = pSrc;
1.283 + }
1.284 + }
1.285 +
1.286 + Mem::FillZ(pZFill, zFillLen);
1.287 +
1.288 + return(p);
1.289 +}
1.290 +
1.291 +/**
1.292 + Zero fill RAM area corresponding to the cluster number aCluster
1.293 + @param aCluster a cluster number to be zero-filled
1.294 +*/
1.295 +void CRamFatTable::ZeroFillCluster(TInt aCluster)
1.296 +{
1.297 + TLinAddr clusterPos= I64LOW(DataPositionInBytes(aCluster));
1.298 + Mem::FillZ(iRamDiskBase+clusterPos, 1<< iOwner->ClusterSizeLog2());
1.299 + }
1.300 +
1.301 +
1.302 +/**
1.303 +Return the location of a Cluster in the data section of the media
1.304 +
1.305 +@param aCluster to find location of
1.306 +@return Byte offset of the cluster data
1.307 +*/
1.308 +TInt64 CRamFatTable::DataPositionInBytes(TUint32 aCluster) const
1.309 + {
1.310 + //__PRINT(_L("CRamFatTable::DataPositionInBytes"));
1.311 + ReadIndirectionTable(aCluster);
1.312 + return(aCluster<<iOwner->ClusterSizeLog2());
1.313 + }
1.314 +
1.315 +/**
1.316 +Allocate and mark as EOF a single cluster as close as possible to aNearestCluster,
1.317 +calls base class implementation but must Enlarge the RAM drive first. Allocated cluster RAM area will be zero-filled.
1.318 +
1.319 +@param aNearestCluster Cluster the new cluster should be nearest to
1.320 +@leave System wide error codes
1.321 +@return The cluster number allocated
1.322 +*/
1.323 +TUint32 CRamFatTable::AllocateSingleClusterL(TUint32 aNearestCluster)
1.324 + {
1.325 + __PRINT(_L("CRamFatTable::AllocateSingleClusterL"));
1.326 + iOwner->EnlargeL(1<<iOwner->ClusterSizeLog2()); // First enlarge the RAM drive
1.327 + TInt fileAllocated=CFatTable::AllocateSingleClusterL(aNearestCluster); // Now update the free cluster and fat/fit
1.328 + ZeroFillCluster(fileAllocated); //-- zero-fill allocated cluster
1.329 + return(fileAllocated);
1.330 + }
1.331 +
1.332 +
1.333 +/**
1.334 + Extend a file or directory cluster chain, enlarging RAM drive first. Allocated clusters are zero-filled.
1.335 + Leaves if there are no free clusters (the disk is full).
1.336 + Note that method now doesn't call CFatTable::ExtendClusterListL() from its base class, be careful making changes there.
1.337 +
1.338 + @param aNumber number of clusters to allocate
1.339 + @param aCluster starting cluster number / ending cluster number after
1.340 + @leave KErrDiskFull + system wide error codes
1.341 +*/
1.342 +void CRamFatTable::ExtendClusterListL(TUint32 aNumber,TInt& aCluster)
1.343 + {
1.344 + __PRINT(_L("CRamFatTable::ExtendClusterListL"));
1.345 + __ASSERT_DEBUG(aNumber>0,Fault(EFatBadParameter));
1.346 +
1.347 + iOwner->EnlargeL(aNumber<<iOwner->ClusterSizeLog2());
1.348 +
1.349 + while(aNumber && GetNextClusterL(aCluster))
1.350 + aNumber--;
1.351 +
1.352 + if(!aNumber)
1.353 + return;
1.354 +
1.355 + if (NumberOfFreeClusters() < aNumber)
1.356 + {
1.357 + __PRINT(_L("CRamFatTable::ExtendClusterListL - leaving KErrDirFull"));
1.358 + User::Leave(KErrDiskFull);
1.359 + }
1.360 +
1.361 + while (aNumber--)
1.362 + {
1.363 + const TInt freeCluster=FindClosestFreeClusterL(aCluster);
1.364 +
1.365 + WriteFatEntryEofL(freeCluster); // Must write EOF for FindClosestFreeCluster to work again
1.366 + DecrementFreeClusterCount(1);
1.367 + WriteL(aCluster,freeCluster);
1.368 + aCluster=freeCluster;
1.369 + ZeroFillCluster(freeCluster); //-- zero fill just allocated cluster (RAM area)
1.370 + }
1.371 +
1.372 + SetFreeClusterHint(aCluster);
1.373 +
1.374 + }
1.375 +
1.376 +/**
1.377 +Mark a chain of clusters as free in the FAT. Shrinks the RAM drive once the
1.378 +clusters are free
1.379 +
1.380 +@param aCluster Start cluster of cluster chain to free
1.381 +@leave System wide error codes
1.382 +*/
1.383 +void CRamFatTable::FreeClusterListL(TUint32 aCluster)
1.384 + {
1.385 + __PRINT1(_L("CRamFatTable::FreeClusterListL aCluster=%d"),aCluster);
1.386 + if (aCluster==0)
1.387 + return; // File has no cluster allocated
1.388 +
1.389 + const TInt clusterShift=iOwner->ClusterSizeLog2();
1.390 + TInt startCluster=aCluster;
1.391 + TInt endCluster=0;
1.392 + TInt totalFreed=0;
1.393 + TLinAddr srcEnd=0;
1.394 +
1.395 + while(endCluster!=EOF_16Bit)
1.396 + {
1.397 + TInt num=CountContiguousClustersL(startCluster,endCluster,KMaxTInt);
1.398 + if (GetNextClusterL(endCluster)==EFalse || endCluster==0)
1.399 + endCluster=EOF_16Bit; // endCluster==0 -> file contained FAT loop
1.400 +
1.401 + // Real position in bytes of the start cluster in the data area
1.402 + TLinAddr startClusterPos= I64LOW(DataPositionInBytes(startCluster));
1.403 + // Sliding value when more than one block is freed
1.404 + TLinAddr trg=startClusterPos-(totalFreed<<clusterShift);
1.405 + __PRINT1(_L("trg=0x%x"),trg);
1.406 +
1.407 + // Beginning of data area to move
1.408 + TLinAddr srcStart=startClusterPos+(num<<clusterShift);
1.409 + __PRINT1(_L("srcStart=0x%x"),srcStart);
1.410 + // Position of next part of cluster chain or position of end of ram drive
1.411 + if (endCluster==EOF_16Bit) // Last cluster is the end of the chain
1.412 + {
1.413 +
1.414 +
1.415 + // Fixed to use the genuine RAM drive size rather than the number
1.416 + // of free clusters - though they *should* be the same
1.417 + // It avoids the problem of iFreeClusters getting out of sync with
1.418 + // the RAM drive size but doesn't solve the issue of why it can happen...
1.419 +
1.420 + srcEnd=I64LOW(iOwner->Size());
1.421 + __PRINT1(_L("srcEnd=0x%x"),srcEnd);
1.422 + }
1.423 + else // Just move up to the next part of the chain
1.424 + srcEnd=I64LOW(DataPositionInBytes(endCluster));
1.425 +
1.426 + //-- Copy (srcEnd-srcStart) bytes from iRamDiskBase+srcStart onto iRamDiskBase+trg
1.427 + //-- zero-filling free space to avoid leaving something important there
1.428 + ASSERT(srcEnd >= srcStart);
1.429 + if(srcEnd-srcStart > 0)
1.430 + {
1.431 + MemCopyFillZ(iRamDiskBase+trg,iRamDiskBase+srcStart,srcEnd-srcStart);
1.432 + }
1.433 + else
1.434 + {//-- we are freeing the cluster chain at the end of the RAMdrive; Nothing to copy to the drive space that has become free,
1.435 + //-- but nevertheless zero fill this space.
1.436 + Mem::FillZ(iRamDiskBase+trg, num<<clusterShift);
1.437 + }
1.438 +
1.439 + totalFreed+=num;
1.440 + startCluster=endCluster;
1.441 + UpdateIndirectionTable(srcStart>>clusterShift,srcEnd>>clusterShift,totalFreed);
1.442 + }
1.443 + TInt bytesFreed=totalFreed<<clusterShift;
1.444 +
1.445 +// First free the cluster list
1.446 + CFatTable::FreeClusterListL(aCluster);
1.447 +// Now reduce the size of the RAM drive
1.448 + iOwner->ReduceSizeL(srcEnd-bytesFreed,bytesFreed);
1.449 + }
1.450 +
1.451 +/**
1.452 +Shift any clusters between aStart and anEnd backwards by aClusterShift
1.453 +
1.454 +@param aStart Start of shift region
1.455 +@param anEnd End of shift region
1.456 +@param aClusterShift amount to shift cluster by
1.457 +*/
1.458 +void CRamFatTable::UpdateIndirectionTable(TUint32 aStart,TUint32 anEnd,TInt aClusterShift)
1.459 + {
1.460 + __PRINT(_L("CRamFatTable::UpdateIndirectionTable"));
1.461 +#if defined(__WINS__)
1.462 + TUint32 count=iOwner->MaxClusterNumber();
1.463 + while (count--)
1.464 + {
1.465 + TUint32 cluster=count;
1.466 + ReadIndirectionTable(cluster);
1.467 + if (cluster>=aStart && cluster<anEnd)
1.468 + WriteIndirectionTable(count,cluster-aClusterShift);
1.469 + }
1.470 +#else
1.471 + TUint16* table=(TUint16*)(RamDiskBase()+iIndirectionTablePos);
1.472 + TUint16* entry=table+iOwner->MaxClusterNumber();
1.473 + while (entry>table)
1.474 + {
1.475 + TUint32 cluster=*--entry;
1.476 + if (cluster<aStart)
1.477 + continue;
1.478 + if (cluster<anEnd)
1.479 + *entry=TUint16(cluster-aClusterShift);
1.480 + }
1.481 +#endif
1.482 + }
1.483 +
1.484 +
1.485 +
1.486 +
1.487 +
1.488 +