os/kernelhwsrv/userlibandfileserver/fileserver/sfat/ram_fat_table.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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\ram_fat_table.cpp
    15 // FAT16 File Allocation Table classes implementation for the RAM media
    16 // 
    17 //
    18 
    19 /**
    20  @file
    21  @internalTechnology
    22 */
    23 
    24 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    25 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    26 //!!
    27 //!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it
    28 //!!
    29 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    30 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    31 
    32 
    33 #include "sl_std.h"
    34 #include "sl_fatcache.h"
    35 #include "fat_table.h"
    36 
    37 
    38 //#######################################################################################################################################
    39 //#     CRamFatTable class implementation 
    40 //#######################################################################################################################################
    41 
    42 /**
    43 Constructor, the RamFatTable allows disk compression by redirecting the FAT
    44 
    45 @param aOwner Owning mount.
    46 */
    47 CRamFatTable::CRamFatTable(CFatMountCB& aOwner)
    48              :CFatTable(aOwner)
    49     {
    50     iFatTablePos=aOwner.FirstFatSector()<<aOwner.SectorSizeLog2();
    51     iIndirectionTablePos=iFatTablePos+aOwner.FatSizeInBytes();
    52     }
    53 
    54 /** factory method */
    55 CRamFatTable* CRamFatTable::NewL(CFatMountCB& aOwner)
    56 {
    57     __PRINT1(_L("CRamFatTable::NewL() drv:%d"),aOwner.DriveNumber());
    58 
    59     CRamFatTable* pSelf = new (ELeave) CRamFatTable(aOwner);
    60 
    61     CleanupStack::PushL(pSelf);
    62     pSelf->InitializeL();
    63     CleanupStack::Pop();
    64 
    65     return pSelf;
    66 }
    67 
    68 void CRamFatTable::InitializeL() 
    69 {
    70     CFatTable::InitializeL();
    71 
    72     ASSERT(iMediaAtt & KMediaAttVariableSize);
    73 
    74     iFatTablePos=iOwner->FirstFatSector()<<iOwner->SectorSizeLog2();
    75     iIndirectionTablePos=iFatTablePos+iOwner->FatSizeInBytes();
    76 
    77     //-- set RAM disk base
    78     TLocalDriveCapsV2 caps;
    79     TPckg<TLocalDriveCapsV2> capsPckg(caps);
    80     User::LeaveIfError(iOwner->LocalDrive()->Caps(capsPckg));
    81   
    82     iRamDiskBase = caps.iBaseAddress; 
    83 }
    84 
    85 /**
    86     Remount the FAT table. This method call means that the media parameters wasn't changed, 
    87     otherwise CFatMountCB::DoReMountL() would reject it. 
    88     Just do some re-initialisation work.
    89 */
    90 void CRamFatTable::ReMountL()
    91 {
    92     //-- re-initialise, actually
    93     ASSERT(iMediaAtt & KMediaAttVariableSize);
    94     ASSERT(FatType() == EFat16);
    95 
    96     iFatTablePos=iOwner->FirstFatSector()<<iOwner->SectorSizeLog2();
    97     iIndirectionTablePos=iFatTablePos+iOwner->FatSizeInBytes();
    98 
    99     //-- set RAM disk base
   100     TLocalDriveCapsV2 caps;
   101     TPckg<TLocalDriveCapsV2> capsPckg(caps);
   102     User::LeaveIfError(iOwner->LocalDrive()->Caps(capsPckg));
   103   
   104     iRamDiskBase = caps.iBaseAddress; 
   105 }
   106 
   107 
   108 /**
   109 Return the start address of the Ram Drive
   110 
   111 @return start address of the Ram Drive 
   112 */
   113 TUint8 *CRamFatTable::RamDiskBase() const
   114     {
   115     return(iRamDiskBase);
   116     }
   117 
   118 
   119 /**
   120 Allocate a new cluster number
   121 
   122 @return New cluster number
   123 */
   124 TInt CRamFatTable::AllocateClusterNumber()
   125     {
   126     return(iOwner->MaxClusterNumber()-NumberOfFreeClusters());
   127     }
   128 
   129 /**
   130 Write a value to the FAT (indirection table) 
   131 
   132 @param aFatIndex Cluster to write to
   133 @param aValue value to write to Fat
   134 @leave 
   135 */
   136 void CRamFatTable::WriteL(TUint32 aFatIndex, TUint32 aValue)
   137     {
   138     //__PRINT(_L("CRamFatTable::WriteL"));
   139 
   140     __ASSERT_ALWAYS(aFatIndex>=2 && (aValue>=2 || aValue==0) && aValue<=0xFFFF,User::Leave(KErrCorrupt));
   141     TUint32 indirectCluster=aFatIndex;
   142     TUint32 indirectClusterNewVal=0;
   143     ReadIndirectionTable(indirectCluster);
   144 //  If value in indirection table!=0 we assume we have already written to the indirection table
   145 //  So just update the FAT table
   146     if (indirectCluster!=0 && aValue!=0)
   147         {
   148         WriteFatTable(aFatIndex,aValue);
   149         return;
   150         }
   151 //  If value in indirection table is 0, we haven't written to it yet, though the memory has
   152 //  already been allocated by the EnlargeL() function
   153     if (indirectCluster==0 && aValue!=0) // Assumes memory has already been allocated
   154         indirectClusterNewVal=AllocateClusterNumber();
   155 //  Write aValue into aFaxIndex and indirectClusterNewVal into the corresponding position
   156 //  in the indirection table    
   157     WriteFatTable(aFatIndex,aValue,indirectClusterNewVal);
   158     }   
   159 
   160 /**
   161 Read the value of a cluster in the Fat
   162 
   163 @param aFatIndex A cluster to read
   164 @leave 
   165 @return The cluster value read
   166 */
   167 
   168 TUint32 CRamFatTable::ReadL(TUint32 aFatIndex) const
   169     {
   170     __ASSERT_ALWAYS(aFatIndex>=KFatFirstSearchCluster,User::Leave(KErrCorrupt));
   171     TUint clusterVal=*(TUint16*)(RamDiskBase()+PosInBytes(aFatIndex)+iFatTablePos);
   172     return(clusterVal);
   173     }
   174 
   175 /**
   176 Write a value to the FAT and indirection table
   177 
   178 @param aFatIndex Cluster number to write to
   179 @param aFatValue Cluster value for Fat
   180 @param anIndirectionValue Value for indirection table
   181 */
   182 void CRamFatTable::WriteFatTable(TInt aFatIndex,TInt aFatValue,TInt anIndirectionValue)
   183     {
   184     TUint8* pos=RamDiskBase()+PosInBytes(aFatIndex);
   185     *(TUint16*)(pos+iFatTablePos)=(TUint16)aFatValue;
   186     *(TUint16*)(pos+iIndirectionTablePos)=(TUint16)anIndirectionValue;
   187     }
   188 
   189 /**
   190 Write to just the fat table
   191 
   192 @param aFatIndex Cluster number to write to
   193 @param aFatValue Cluster value for Fat
   194 */
   195 void CRamFatTable::WriteFatTable(TInt aFatIndex,TInt aFatValue)
   196     {
   197     *(TUint16*)(RamDiskBase()+PosInBytes(aFatIndex)+iFatTablePos)=(TUint16)aFatValue;
   198     }
   199 
   200 /**
   201 Write to just the fat table
   202 
   203 @param aFatIndex Cluster number to write to
   204 @param aFatValue Value for indirection table
   205 */
   206 void CRamFatTable::WriteIndirectionTable(TInt aFatIndex,TInt aFatValue)
   207     {
   208     *(TUint16*)(RamDiskBase()+PosInBytes(aFatIndex)+iIndirectionTablePos)=(TUint16)aFatValue;
   209     }
   210 
   211 /**
   212 Find the real location of aCluster
   213 
   214 @param aCluster Cluster to read, contians cluster value upon return
   215 */
   216 void CRamFatTable::ReadIndirectionTable(TUint32& aCluster) const
   217     {
   218     aCluster=*(TUint16*)(RamDiskBase()+PosInBytes(aCluster)+iIndirectionTablePos);
   219     }
   220 
   221 /**
   222 Copy memory in RAM drive area, unlocking required
   223 
   224 @param aTrg Pointer to destination location
   225 @param aSrc Pointer to source location
   226 @param aLength Length of data to copy
   227 @return Pointer to end of data copied
   228 */
   229 TUint8* CRamFatTable::MemCopy(TAny* aTrg,const TAny* aSrc,TInt aLength)
   230     {
   231     TUint8* p=Mem::Copy(aTrg,aSrc,aLength);
   232     return(p);
   233     }
   234 
   235 /**
   236     Copy memory with filling the source buffer with zeroes. Target and source buffers can overlap.
   237     Used on RAMDrive srinking in order to wipe data from the file that is being deleted.
   238     
   239     @param   aTrg       pointer to the target address
   240     @param   aSrc       pointer to the destination address
   241     @param   aLength    how many bytes to copy
   242     @return  A pointer to a location aLength bytes beyond aTrg (i.e. the location aTrg+aLength).
   243 */
   244 TUint8* CRamFatTable::MemCopyFillZ(TAny* aTrg, TAny* aSrc,TInt aLength)
   245 {
   246     //-- just copy src to the trg, the memory areas can overlap.
   247     TUint8* p=Mem::Copy(aTrg, aSrc, aLength);
   248     
   249     //-- now zero-fill the source memory area taking into account possible overlap.
   250     TUint8* pSrc = static_cast<TUint8*>(aSrc);
   251     TUint8* pTrg = static_cast<TUint8*>(aTrg);
   252     
   253     TUint8* pZFill = NULL; //-- pointer to the beginning of zerofilled area
   254     TInt    zFillLen = 0;  //-- a number of bytes to zero-fill
   255     
   256     if(aTrg < aSrc)
   257     {
   258         if(pTrg+aLength < pSrc)
   259         {//-- target and source areas do not overlap
   260          pZFill = pSrc;
   261          zFillLen = aLength;
   262         }
   263         else
   264         {//-- target and source areas overlap, try not to corrupt the target area
   265          zFillLen = pSrc-pTrg;
   266          pZFill = pTrg+aLength;
   267         }
   268     }
   269     else
   270     {
   271         if(pSrc+aLength < pTrg)
   272         {//-- target and source areas do not overlap
   273          pZFill = pSrc;
   274          zFillLen = aLength;
   275         }
   276         else
   277         {//-- target and source areas overlap, try not to corrupt the target area
   278          zFillLen = pSrc+aLength-pTrg;
   279          pZFill = pSrc;
   280         }
   281     }
   282 
   283     Mem::FillZ(pZFill, zFillLen);
   284 
   285     return(p);
   286 }
   287 
   288 /**
   289     Zero fill RAM area corresponding to the cluster number aCluster
   290     @param  aCluster a cluster number to be zero-filled
   291 */
   292 void CRamFatTable::ZeroFillCluster(TInt aCluster)
   293 {
   294         TLinAddr clusterPos= I64LOW(DataPositionInBytes(aCluster));
   295         Mem::FillZ(iRamDiskBase+clusterPos, 1<< iOwner->ClusterSizeLog2());     
   296     }
   297 
   298 
   299 /**
   300 Return the location of a Cluster in the data section of the media
   301 
   302 @param aCluster to find location of
   303 @return Byte offset of the cluster data 
   304 */
   305 TInt64 CRamFatTable::DataPositionInBytes(TUint32 aCluster) const
   306     {
   307     //__PRINT(_L("CRamFatTable::DataPositionInBytes"));
   308     ReadIndirectionTable(aCluster);
   309     return(aCluster<<iOwner->ClusterSizeLog2());
   310     }
   311 
   312 /**
   313 Allocate and mark as EOF a single cluster as close as possible to aNearestCluster,
   314 calls base class implementation but must Enlarge the RAM drive first. Allocated cluster RAM area will be zero-filled.
   315 
   316 @param  aNearestCluster Cluster the new cluster should be nearest to
   317 @leave  System wide error codes
   318 @return The cluster number allocated
   319 */
   320 TUint32 CRamFatTable::AllocateSingleClusterL(TUint32 aNearestCluster)
   321     {
   322     __PRINT(_L("CRamFatTable::AllocateSingleClusterL"));
   323     iOwner->EnlargeL(1<<iOwner->ClusterSizeLog2()); //  First enlarge the RAM drive
   324     TInt fileAllocated=CFatTable::AllocateSingleClusterL(aNearestCluster); //   Now update the free cluster and fat/fit
   325     ZeroFillCluster(fileAllocated);  //-- zero-fill allocated cluster 
   326     return(fileAllocated);
   327     }   
   328 
   329 
   330 /**
   331     Extend a file or directory cluster chain, enlarging RAM drive first. Allocated clusters are zero-filled.
   332     Leaves if there are no free clusters (the disk is full).
   333     Note that method now doesn't call CFatTable::ExtendClusterListL() from its base class, be careful making changes there.
   334 
   335     @param aNumber      number of clusters to allocate
   336     @param aCluster     starting cluster number / ending cluster number after
   337     @leave              KErrDiskFull + system wide error codes
   338 */
   339 void CRamFatTable::ExtendClusterListL(TUint32 aNumber,TInt& aCluster)
   340     {
   341     __PRINT(_L("CRamFatTable::ExtendClusterListL"));
   342     __ASSERT_DEBUG(aNumber>0,Fault(EFatBadParameter));
   343     
   344     iOwner->EnlargeL(aNumber<<iOwner->ClusterSizeLog2());
   345 
   346     while(aNumber && GetNextClusterL(aCluster))
   347         aNumber--;
   348 
   349     if(!aNumber)
   350         return;
   351 
   352     if (NumberOfFreeClusters() < aNumber)
   353         {
   354         __PRINT(_L("CRamFatTable::ExtendClusterListL - leaving KErrDirFull"));
   355         User::Leave(KErrDiskFull);
   356         }
   357 
   358     while (aNumber--)
   359         {
   360         const TInt freeCluster=FindClosestFreeClusterL(aCluster);
   361 
   362         WriteFatEntryEofL(freeCluster); //  Must write EOF for FindClosestFreeCluster to work again
   363         DecrementFreeClusterCount(1);
   364         WriteL(aCluster,freeCluster);
   365         aCluster=freeCluster;
   366         ZeroFillCluster(freeCluster); //-- zero fill just allocated cluster (RAM area)
   367         }
   368 
   369     SetFreeClusterHint(aCluster); 
   370   
   371     }
   372 
   373 /**
   374 Mark a chain of clusters as free in the FAT. Shrinks the RAM drive once the
   375 clusters are free 
   376 
   377 @param aCluster Start cluster of cluster chain to free
   378 @leave System wide error codes
   379 */
   380 void CRamFatTable::FreeClusterListL(TUint32 aCluster)
   381     {
   382     __PRINT1(_L("CRamFatTable::FreeClusterListL aCluster=%d"),aCluster);
   383     if (aCluster==0)
   384         return; // File has no cluster allocated
   385 
   386     const TInt clusterShift=iOwner->ClusterSizeLog2();
   387     TInt startCluster=aCluster;
   388     TInt endCluster=0;
   389     TInt totalFreed=0;
   390     TLinAddr srcEnd=0;
   391 
   392     while(endCluster!=EOF_16Bit)
   393         {
   394         TInt num=CountContiguousClustersL(startCluster,endCluster,KMaxTInt);
   395         if (GetNextClusterL(endCluster)==EFalse || endCluster==0)
   396             endCluster=EOF_16Bit;   // endCluster==0 -> file contained FAT loop
   397 
   398     //  Real position in bytes of the start cluster in the data area
   399         TLinAddr startClusterPos= I64LOW(DataPositionInBytes(startCluster));
   400     //  Sliding value when more than one block is freed
   401         TLinAddr trg=startClusterPos-(totalFreed<<clusterShift);
   402         __PRINT1(_L("trg=0x%x"),trg);
   403 
   404     //  Beginning of data area to move
   405         TLinAddr srcStart=startClusterPos+(num<<clusterShift);
   406         __PRINT1(_L("srcStart=0x%x"),srcStart);
   407     //  Position of next part of cluster chain or position of end of ram drive
   408         if (endCluster==EOF_16Bit)  //  Last cluster is the end of the chain
   409             {
   410         
   411     
   412         //  Fixed to use the genuine RAM drive size rather than the number
   413         //  of free clusters - though they *should* be the same
   414         //  It avoids the problem of iFreeClusters getting out of sync with 
   415         //  the RAM drive size but doesn't solve the issue of why it can happen...
   416             
   417             srcEnd=I64LOW(iOwner->Size());
   418             __PRINT1(_L("srcEnd=0x%x"),srcEnd);
   419             }
   420         else                        //  Just move up to the next part of the chain
   421             srcEnd=I64LOW(DataPositionInBytes(endCluster));
   422 
   423         //-- Copy (srcEnd-srcStart) bytes from iRamDiskBase+srcStart onto iRamDiskBase+trg
   424         //-- zero-filling free space to avoid leaving something important there
   425         ASSERT(srcEnd >= srcStart);
   426         if(srcEnd-srcStart > 0)
   427             { 
   428             MemCopyFillZ(iRamDiskBase+trg,iRamDiskBase+srcStart,srcEnd-srcStart);
   429             }    
   430         else
   431             {//-- we are freeing the cluster chain at the end of the RAMdrive; Nothing to copy to the drive space that has become free,
   432              //-- but nevertheless zero fill this space.
   433             Mem::FillZ(iRamDiskBase+trg, num<<clusterShift);
   434             }    
   435         
   436         totalFreed+=num;
   437         startCluster=endCluster;
   438         UpdateIndirectionTable(srcStart>>clusterShift,srcEnd>>clusterShift,totalFreed);
   439         }
   440     TInt bytesFreed=totalFreed<<clusterShift;
   441     
   442 //  First free the cluster list
   443     CFatTable::FreeClusterListL(aCluster);
   444 //  Now reduce the size of the RAM drive
   445     iOwner->ReduceSizeL(srcEnd-bytesFreed,bytesFreed);
   446     }
   447 
   448 /**
   449 Shift any clusters between aStart and anEnd backwards by aClusterShift
   450 
   451 @param aStart Start of shift region
   452 @param anEnd End of shift region
   453 @param aClusterShift amount to shift cluster by
   454 */
   455 void CRamFatTable::UpdateIndirectionTable(TUint32 aStart,TUint32 anEnd,TInt aClusterShift)
   456     {
   457     __PRINT(_L("CRamFatTable::UpdateIndirectionTable"));
   458 #if defined(__WINS__)
   459     TUint32 count=iOwner->MaxClusterNumber();
   460     while (count--)
   461         {
   462         TUint32 cluster=count;
   463         ReadIndirectionTable(cluster);
   464         if (cluster>=aStart && cluster<anEnd)
   465             WriteIndirectionTable(count,cluster-aClusterShift);
   466         }
   467 #else
   468     TUint16* table=(TUint16*)(RamDiskBase()+iIndirectionTablePos);
   469     TUint16* entry=table+iOwner->MaxClusterNumber();
   470     while (entry>table)
   471         {
   472         TUint32 cluster=*--entry;
   473         if (cluster<aStart)
   474             continue;
   475         if (cluster<anEnd)
   476             *entry=TUint16(cluster-aClusterShift);
   477         }
   478 #endif
   479     }
   480 
   481 
   482 
   483 
   484 
   485