userlibandfileserver/fileserver/sfat/ram_fat_table.cpp
changeset 9 96e5fb8b040d
equal deleted inserted replaced
-1:000000000000 9:96e5fb8b040d
       
     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