userlibandfileserver/fileserver/sfat32/sl_vfat.cpp
changeset 90 947f0dc9f7a8
parent 15 4122176ea935
child 109 b3a1d9898418
equal deleted inserted replaced
52:2d65c2f76d7b 90:947f0dc9f7a8
    28 
    28 
    29 // use second half of ISO Latin 1 character set for extended chars
    29 // use second half of ISO Latin 1 character set for extended chars
    30 const TUint KExtendedCharStart=0x80;
    30 const TUint KExtendedCharStart=0x80;
    31 const TUint KExtendedCharEnd=0xff;
    31 const TUint KExtendedCharEnd=0xff;
    32 
    32 
    33 LOCAL_C TBool IsLegalChar(TChar aCharacter,TBool aAllowWildChars,TBool aUseExtendedChars=EFalse,TBool aInScanDrive=EFalse)
    33 const TUint KMaxVFatEntries = 21; ///< Max possible number of entries in the VFAT entryset
    34 //
    34 
    35 // Returns ETrue if aCharacter is legal inside a dos filename
    35 
    36 //
    36 //-----------------------------------------------------------------------------
       
    37 /**
       
    38     Returns ETrue if aCharacter is legal inside a dos filename
       
    39 */
       
    40 static TBool IsLegalChar(TChar aCharacter,TBool aAllowWildChars,TBool aUseExtendedChars=EFalse,TBool aInScanDrive=EFalse)
    37 	{
    41 	{
    38 	if ((aCharacter==KMatchOne) || (aCharacter==KMatchAny))
    42 	if ((aCharacter==KMatchOne) || (aCharacter==KMatchAny))
    39 		return(aAllowWildChars);
    43 		return(aAllowWildChars);
    40 	if ((TUint)aCharacter < 0x20)
    44 	if ((TUint)aCharacter < 0x20)
    41 	    return EFalse;
    45 	    return EFalse;
    44     if (aInScanDrive)
    48     if (aInScanDrive)
    45     	return ETrue;
    49     	return ETrue;
    46 	return LocaleUtils::IsLegalShortNameCharacter(aCharacter,aUseExtendedChars);
    50 	return LocaleUtils::IsLegalShortNameCharacter(aCharacter,aUseExtendedChars);
    47 	}
    51 	}
    48 
    52 
    49 LOCAL_C void ReplaceFirstCharacterIfClashesWithE5L(TDes8& aShortName)
    53 //-----------------------------------------------------------------------------
       
    54 static void ReplaceFirstCharacterIfClashesWithE5L(TDes8& aShortName)
    50 	{
    55 	{
    51 	if (0 < aShortName.Length() && aShortName[0] == KEntryErasedMarker)
    56 	if (0 < aShortName.Length() && aShortName[0] == KEntryErasedMarker)
    52 		{
    57 		{
    53 		aShortName[0] = KLeadingE5Replacement;
    58 		aShortName[0] = KLeadingE5Replacement;
    54 		}
    59 		}
    55 	}
    60 	}
    56 
    61 
    57 LOCAL_C void ReplaceIllegalCharactersL(TDes& aLongName, TUint aCharacterToReplaceWith)
    62 //-----------------------------------------------------------------------------
       
    63 static void ReplaceIllegalCharactersL(TDes& aLongName, TUint aCharacterToReplaceWith)
    58 	{
    64 	{
    59 	TBool alreadyFoundExtensionDelimiter=EFalse;
    65 	TBool alreadyFoundExtensionDelimiter=EFalse;
    60 
    66 
    61 	TInt LongNameLen = aLongName.Length();
    67 	TInt LongNameLen = aLongName.Length();
    62 	TInt extDelimiterIndex = aLongName.LocateReverse(KExtDelimiter);
    68 	TInt extDelimiterIndex = aLongName.LocateReverse(KExtDelimiter);
   128 				}
   134 				}
   129 			}
   135 			}
   130 		}
   136 		}
   131 	}
   137 	}
   132 
   138 
       
   139 //-----------------------------------------------------------------------------
       
   140 /**
       
   141     Create a legal shortname from aLongName
       
   142 */
   133 TShortName DoGenerateShortNameL(const TDesC& aLongName,TInt& aNum,TBool aUseTildeSelectively)
   143 TShortName DoGenerateShortNameL(const TDesC& aLongName,TInt& aNum,TBool aUseTildeSelectively)
   134 //
       
   135 // Create a legal shortname from aLongName
       
   136 //
       
   137 	{
   144 	{
   138 
   145 
   139 	TFileName longName(aLongName);
   146 	TFileName longName(aLongName);
   140 	longName.UpperCase();
   147 	longName.UpperCase();
   141 	ReplaceIllegalCharactersL(longName, '_');
   148 	ReplaceIllegalCharactersL(longName, '_');
   257 	
   264 	
   258 	ReplaceFirstCharacterIfClashesWithE5L(shortName);		
   265 	ReplaceFirstCharacterIfClashesWithE5L(shortName);		
   259 	return shortName;
   266 	return shortName;
   260 	}
   267 	}
   261 
   268 
   262 
   269 //-----------------------------------------------------------------------------
   263 /**
   270 /**
   264 Check whether a Dos name is legal or not.
   271 Check whether a Dos name is legal or not.
   265 
   272 
   266 @param aName                The entry name to be analysed (may be represented as TDes16& or TDes8&)
   273 @param aName                The entry name to be analysed (may be represented as TDes16& or TDes8&)
   267 @param anAllowWildCards	    Flag to indicate whether to allow wildcards in name or not
   274 @param anAllowWildCards	    Flag to indicate whether to allow wildcards in name or not
   269 @param aInScanDrive         Flag to indicate whether called when scanning drive
   276 @param aInScanDrive         Flag to indicate whether called when scanning drive
   270 @param aAllowLowerCase      ETrue to allow lower case in the analysed DOS name
   277 @param aAllowLowerCase      ETrue to allow lower case in the analysed DOS name
   271 
   278 
   272 @return ETrue if the name is a legal DOS one.
   279 @return ETrue if the name is a legal DOS one.
   273 */
   280 */
   274 
       
   275 static TBool DoCheckLegalDosName(const TDesC& aName, TBool anAllowWildCards, TBool aUseExtendedChars, TBool aInScanDrive, TBool aAllowLowerCase, TBool aIsForFileCreation)
   281 static TBool DoCheckLegalDosName(const TDesC& aName, TBool anAllowWildCards, TBool aUseExtendedChars, TBool aInScanDrive, TBool aAllowLowerCase, TBool aIsForFileCreation)
   276 	{
   282 	{
   277     const TInt count=aName.Length();
   283     const TInt count=aName.Length();
   278 	if (count==0)
   284 	if (count==0)
   279 		return EFalse;
   285 		return EFalse;
   386 		}
   392 		}
   387 
   393 
   388 	return ETrue;
   394 	return ETrue;
   389 	}
   395 	}
   390 
   396 
       
   397 //-----------------------------------------------------------------------------
   391 /**
   398 /**
   392     Check whether a Dos name is legal or not. Unicode version
   399     Check whether a Dos name is legal or not. Unicode version
   393     parameters and return value absolutely the same as in DoCheckLegalDosName()
   400     parameters and return value absolutely the same as in DoCheckLegalDosName()
   394 */
   401 */
   395 TBool IsLegalDosName(const TDesC16& aName, TBool anAllowWildCards, TBool aUseExtendedChars, TBool aInScanDrive, TBool aAllowLowerCase, TBool aIsForFileCreation)
   402 TBool IsLegalDosName(const TDesC16& aName, TBool anAllowWildCards, TBool aUseExtendedChars, TBool aInScanDrive, TBool aAllowLowerCase, TBool aIsForFileCreation)
   396 	{
   403 	{
   397 
   404 
   398 	__PRINT(_L("IsLegalDosName 16"));
   405 	//__PRINT(_L("IsLegalDosName 16"));
   399 
   406 
   400     return DoCheckLegalDosName(aName, anAllowWildCards, aUseExtendedChars, aInScanDrive, aAllowLowerCase, aIsForFileCreation);	
   407     return DoCheckLegalDosName(aName, anAllowWildCards, aUseExtendedChars, aInScanDrive, aAllowLowerCase, aIsForFileCreation);	
   401 	}
   408 	}
   402 
   409 
       
   410 //-----------------------------------------------------------------------------
       
   411 /**
       
   412     Returns ETrue and the entryPos of aName if found or EFalse
       
   413 */
   403 TBool CFatMountCB::FindShortNameL(const TShortName& aName,TEntryPos& anEntryPos)
   414 TBool CFatMountCB::FindShortNameL(const TShortName& aName,TEntryPos& anEntryPos)
   404 //
   415 	{
   405 // Returns ETrue and the entryPos of aName if found or EFalse
   416 	
   406 //
   417 	__PRINT(_L("CFatMountCB::FindShortNameL"));	
   407 	{
       
   408 	
       
   409 	__PRINT(_L("VFAT::CFatMountCB::FindShortNameL"));	
       
   410 	TFatDirEntry fatEntry;
   418 	TFatDirEntry fatEntry;
   411 	TInt count=0;
   419 	TInt count=0;
   412 	FOREVER
   420 	FOREVER
   413 		{
   421 		{
   414 		count++;
   422 		count++;
   426 			break;//Allows maximum number of entries in root directory
   434 			break;//Allows maximum number of entries in root directory
   427 		}
   435 		}
   428 	return EFalse;
   436 	return EFalse;
   429 	}
   437 	}
   430 	
   438 	
   431 TBool CFatMountCB::IsUniqueNameL(const TShortName& aName,TInt aDirCluster)
   439 //-----------------------------------------------------------------------------
   432 //
   440 /**
   433 // Returns ETrue if aName is unique, EFalse if a matching name is found.
   441     Returns ETrue if aName is unique, EFalse if a matching name is found.
   434 //
   442 */
   435 	{
   443 TBool CFatMountCB::IsUniqueNameL(const TShortName& aName, TUint32 aDirCluster)
   436 
   444 	{
   437 	__PRINT(_L("VFAT::CFatMountCB::IsUniqueNameL"));	
   445 
       
   446 	__PRINT(_L("CFatMountCB::IsUniqueNameL"));	
   438 	TEntryPos entryPos(aDirCluster,0);
   447 	TEntryPos entryPos(aDirCluster,0);
   439 	if (FindShortNameL(aName,entryPos))
   448 	return ! FindShortNameL(aName,entryPos);
   440 		return(EFalse);
   449 	}
   441 	return(ETrue);
   450 
   442 	}
   451 //-----------------------------------------------------------------------------
   443 
   452 /**
       
   453     A legal dos name has been typed that clashes with a computer generated shortname
       
   454     Change the shortname to something else.
       
   455 */
   444 void CFatMountCB::ReplaceClashingNameL(const TShortName& aNewName,const TEntryPos& anEntryPos)
   456 void CFatMountCB::ReplaceClashingNameL(const TShortName& aNewName,const TEntryPos& anEntryPos)
   445 //
   457 	{
   446 // A legal dos name has been typed that clashes with a computer generated shortname
   458 
   447 // Change the shortname to something else.
   459 	__PRINT(_L("CFatMountCB::ReplaceClashingNameL"));	
   448 //
       
   449 	{
       
   450 
       
   451 	__PRINT(_L("VFAT::CFatMountCB::ReplaceClashingNameL"));	
       
   452 	TFatDirEntry entry;
   460 	TFatDirEntry entry;
   453 	ReadDirEntryL(anEntryPos,entry);
   461 	ReadDirEntryL(anEntryPos,entry);
   454 	__ASSERT_ALWAYS(entry.IsEndOfDirectory()==EFalse,User::Leave(KErrCorrupt));
   462 	__ASSERT_ALWAYS(entry.IsEndOfDirectory()==EFalse,User::Leave(KErrCorrupt));
   455 	entry.SetName(aNewName);
   463 	entry.SetName(aNewName);
   456 	WriteDirEntryL(anEntryPos,entry);
   464 	WriteDirEntryL(anEntryPos,entry);
   467 		if (entry.iData[0]&0x40)
   475 		if (entry.iData[0]&0x40)
   468 			break;
   476 			break;
   469 		}
   477 		}
   470 	}
   478 	}
   471 
   479 
   472 TBool CFatMountCB::GenerateShortNameL(TInt aDirCluster,const TDesC& aName,TShortName& aGeneratedName, TBool aForceRandomize)
   480 /**
   473 //
   481     Generate a legal dos filename as an alias for aName.
   474 // Generate a legal dos filename as an alias for aName.
   482     @return ETrue if aName is a legal dos name.
   475 // Returns ETrue if aName is a legal dos name.
   483 */
   476 //
   484 TBool CFatMountCB::GenerateShortNameL(TUint32 aDirCluster,const TDesC& aName,TShortName& aGeneratedName, TBool aForceRandomize)
   477 	{
   485 	{
   478 
   486 
   479 	__PRINT(_L("VFAT::CFatMountCB::GenerateShortNameL"));
   487 	__PRINT1(_L("CFatMountCB::GenerateShortNameL() cl:%d"), aDirCluster);
       
   488 
       
   489     if(!ClusterNumberValid(aDirCluster))
       
   490         {
       
   491         ASSERT(0);
       
   492         User::Leave(KErrCorrupt);
       
   493         }
       
   494 
   480 	// Given the long file-name "ABCDEFGHI.TXT", EPOC used to generate short 
   495 	// Given the long file-name "ABCDEFGHI.TXT", EPOC used to generate short 
   481 	// file-names in the following pecking order:
   496 	// file-names in the following pecking order:
   482 	//     "ABCDEFGH.TXT",
   497 	//     "ABCDEFGH.TXT",
   483 	//     "ABCDEF~0.TXT",
   498 	//     "ABCDEF~0.TXT",
   484 	//     "ABCDEF~1.TXT",
   499 	//     "ABCDEF~1.TXT",
   544 		}
   559 		}
   545 
   560 
   546 
   561 
   547 	}
   562 	}
   548 
   563 
   549 void TFatDirEntry::InitializeAsVFat(TUint8 aCheckSum)
   564 
   550 //
   565 //-----------------------------------------------------------------------------
   551 // Initialize a FAT entry as a VFAT filename
   566 /**
   552 //
   567     Write up to KMaxVFatEntryName unicode chars from aName to the entry
   553 	{
   568     @param  aName       long file name part that will be converted into the VFAT entryset
   554 
   569     @param  aLen        length of the remaining name
   555 	Mem::Fill(this,sizeof(SFatDirEntry),0xFF);
   570     @param  aCheckSum   DOS entry name checksum.
       
   571 */
       
   572 void TFatDirEntry::SetVFatEntry(const TDesC& aName, TUint aLen, TUint8 aCheckSum)
       
   573 	{
       
   574     //-- LFN in the last entry must be padded with FFs
       
   575     Mem::Fill(iData,sizeof(iData),0xFF);
       
   576 
       
   577     //-- initialise some VFAT entry specific fields
   556 	iData[0x0B]=0x0F;
   578 	iData[0x0B]=0x0F;
   557 	iData[0x0C]=0x00; iData[0x0D]=aCheckSum;
   579 	iData[0x0C]=0x00; iData[0x0D]=aCheckSum;
   558 	iData[0x1A]=0x00; iData[0x1B]=0x00;
   580 	iData[0x1A]=0x00; iData[0x1B]=0x00;
   559 	}
       
   560 
       
   561 void TFatDirEntry::SetVFatEntry(const TDesC& aName,TInt aLen)
       
   562 //
       
   563 // Write up to KMaxVFatEntryName unicode chars from aName to the entry
       
   564 //
       
   565 	{
       
   566 
   581 
   567 	TInt rem=aName.Length()-aLen;
   582 	TInt rem=aName.Length()-aLen;
   568 	TPtrC section(aName.Ptr()+aLen,Min(rem,KMaxVFatEntryName));
   583 	TPtrC section(aName.Ptr()+aLen,Min(rem,KMaxVFatEntryName));
   569 	TBuf16<KMaxVFatEntryName> buf16;
   584 	TBuf16<KMaxVFatEntryName> buf16;
   570 	buf16.Copy(section);
   585 	buf16.Copy(section);
       
   586 	
   571 	if (rem<KMaxVFatEntryName)
   587 	if (rem<KMaxVFatEntryName)
   572 		{
   588 		{
   573 		rem++;
   589 		rem++;
   574 		buf16.ZeroTerminate();
   590 		buf16.ZeroTerminate();
   575 		buf16.SetLength(rem); // Zero termination doesn't increase the buf length
   591 		buf16.SetLength(rem); // Zero termination doesn't increase the buf length
   576 		}
   592 		}
       
   593 
   577 	TUint8 orderNo=(TUint8)(aLen/KMaxVFatEntryName+1);
   594 	TUint8 orderNo=(TUint8)(aLen/KMaxVFatEntryName+1);
   578 	TInt s=Min(rem,5);
   595 	TInt s=Min(rem,5);
   579 	Mem::Copy(&iData[0x01],buf16.Ptr(),s*2);//Copy up to 10 bytes of buf16 into iData
   596 	Mem::Copy(&iData[0x01],buf16.Ptr(),s*2);//Copy up to 10 bytes of buf16 into iData
       
   597 	
   580 	TInt offset=s;
   598 	TInt offset=s;
   581 	rem-=s;
   599 	rem-=s;
   582 	s=Min(rem,6);
   600 	s=Min(rem,6);
   583 	Mem::Copy(&iData[0x0E],buf16.Ptr()+offset,s*2);
   601 	Mem::Copy(&iData[0x0E],buf16.Ptr()+offset,s*2);
       
   602 	
   584 	offset+=s;
   603 	offset+=s;
   585 	rem-=s;
   604 	rem-=s;
       
   605 	
   586 	s=Min(rem,2);
   606 	s=Min(rem,2);
   587 	Mem::Copy(&iData[0x1C],buf16.Ptr()+offset,s*2);
   607 	Mem::Copy(&iData[0x1C],buf16.Ptr()+offset,s*2);
   588 	rem-=s;
   608 	rem-=s;
       
   609 
   589 	if (rem==0)
   610 	if (rem==0)
   590 		orderNo|=0x40;
   611 		orderNo|=0x40;
       
   612 
   591 	iData[0]=orderNo;
   613 	iData[0]=orderNo;
   592 	}
   614 	}
   593 
   615 
       
   616 
       
   617 //-----------------------------------------------------------------------------
       
   618 /**
       
   619     Read KMaxVFatEntryName unicode chars from the entry
       
   620 */
   594 void TFatDirEntry::ReadVFatEntry(TDes16& aBuf) const
   621 void TFatDirEntry::ReadVFatEntry(TDes16& aBuf) const
   595 //
   622 	{
   596 // Read KMaxVFatEntryName unicode chars from the entry
       
   597 //
       
   598 	{
       
   599 
       
   600 	aBuf.SetLength(KMaxVFatEntryName);
   623 	aBuf.SetLength(KMaxVFatEntryName);
   601 	Mem::Copy(&aBuf[0],&iData[0x01],5*2);
   624 	Mem::Copy(&aBuf[0],&iData[0x01],5*2);
   602 	Mem::Copy(&aBuf[5],&iData[0x0E],6*2);
   625 	Mem::Copy(&aBuf[5],&iData[0x0E],6*2);
   603 	Mem::Copy(&aBuf[11],&iData[0x1C],2*2);
   626 	Mem::Copy(&aBuf[11],&iData[0x1C],2*2);
   604 	}
   627 	}
   605 
   628 
   606 void CFatMountCB::WriteDirEntryL(TEntryPos& aPos,const TFatDirEntry& aFatDirEntry,const TDesC& aLongName)
   629 //-----------------------------------------------------------------------------
   607 //
   630 /**
   608 // Write a VFAT directory entry to disk at position aPos - leave aPos refering to the dos entry
   631     Write a VFAT directory entry set to disk at position aPos - leave aPos refering to the dos entry
   609 // Assumes sufficient space has been created for it by AddDirEntry.
   632     Assumes sufficient space has been created for it by AddDirEntry.
   610 //
   633     For Rugged FAT mode bulk writing of the whole entryset is OK. If the entryset fits into media atomic write unit, the 
   611 	{
   634     write is transactional anyway. if the entryset is split between media atomic write units, the part of it with the DOS
   612 
   635     entry is written last; if this write operation fails, the artifact would be just several orphaned VFAT entries; 
   613 	__PRINT(_L("VFAT::CFatMountCB::WriteDirEntryL"));	
   636 
       
   637     @param  aPos            in: specifies the entryste start position. out: points to the last (DOS) entry in the created entryset
       
   638     @param  aFatDirEntry    aDosEntry DOS entry
       
   639     @param  aLongName       VFAT entry long name
       
   640 */
       
   641 void CFatMountCB::WriteDirEntryL(TEntryPos& aPos, const TFatDirEntry& aDosEntry, const TDesC& aLongName)
       
   642     {
       
   643     __PRINT2(_L("CFatMountCB::WriteDirEntryL() cl:%d, pos:%d"), aPos.Cluster(), aPos.Pos());   
   614 	__ASSERT_DEBUG(aLongName.Length(),Fault(EVFatNoLongName));
   644 	__ASSERT_DEBUG(aLongName.Length(),Fault(EVFatNoLongName));
   615 	TEntryPos startPos(aPos.iCluster,aPos.iPos);
   645 
   616 	TUint8  localBuf[KDefaultSectorSize];
   646     //-- scratch buffer for whole VFAT entryset. Max number of entries in it is 21 entry or 672 bytes. 
   617 	TUint8 cksum=CalculateShortNameCheckSum(aFatDirEntry.Name());
   647     //-- in the worst case the entryset can span across 3 clusters (512 bytes per cluster)
   618 	TInt numEntries=NumberOfVFatEntries(aLongName.Length())-1; // Excluding dos entry
   648     //-- Using the scratch buffer is not ideal, but write-back directory cache isn't in place yet
   619 	// see if all entries written to one sector
   649     const TUint KBufSize = 680;
   620 	// single sector writes not supported if sector size>default size 
   650     TUint8  scratchBuf[KBufSize];
   621 	TInt dosOffset=numEntries<<KSizeOfFatDirEntryLog2;
   651 
   622 	TInt absolutePos=(aPos.iCluster<<ClusterSizeLog2())+ClusterRelativePos(aPos.iPos);
   652     const TUint8    cksum=CalculateShortNameCheckSum(aDosEntry.Name());
   623 	TBool isSameSector=(((absolutePos^(absolutePos+dosOffset))>>SectorSizeLog2())==0 && ((TUint)(1<<SectorSizeLog2())<=KDefaultSectorSize));
   653     TUint           numEntries=NumberOfVFatEntries(aLongName.Length())-1; // Excluding dos entry
   624 	TFatDirEntry vFatEntry;
   654 
   625 	vFatEntry.InitializeAsVFat(cksum);
   655     ASSERT(KBufSize >= ((numEntries+1)<<KSizeOfFatDirEntryLog2));
   626 	TInt offset=0;
   656     TEntryPos startPos;
       
   657 
       
   658     for(;;)
       
   659         {
       
   660         TInt posInBuf = 0;
       
   661         startPos = aPos;
       
   662         TBool movedCluster = EFalse;
       
   663 
       
   664         TUint nRemLen = KMaxVFatEntryName*(numEntries-1);
       
   665 
       
   666         while(numEntries)
       
   667             {
       
   668             TFatDirEntry* pEntry = (TFatDirEntry*)(&scratchBuf[posInBuf]);
       
   669             
       
   670             pEntry->SetVFatEntry(aLongName, nRemLen, cksum);  
       
   671 
       
   672             posInBuf += KSizeOfFatDirEntry;
       
   673             MoveToNextEntryL(aPos);
       
   674 
       
   675             numEntries--;
       
   676             movedCluster = (startPos.Cluster() != aPos.Cluster()); //-- if moved to another cluser, need to flush buffer
       
   677             
       
   678             if(!numEntries || movedCluster)
       
   679                 break; //-- VFAT entryset is completed
       
   680             
       
   681             ASSERT(nRemLen >= (TUint)KMaxVFatEntryName);
       
   682             nRemLen -= KMaxVFatEntryName;
       
   683             }
       
   684     
       
   685         if(movedCluster)
       
   686             {
       
   687             DirWriteL(startPos, TPtrC8(&scratchBuf[0], posInBuf));
       
   688             continue;
       
   689             }    
       
   690 
       
   691         if(!numEntries)
       
   692             {//-- need to append DOS entry
       
   693             Mem::Copy(&scratchBuf[posInBuf], &aDosEntry, KSizeOfFatDirEntry);    
       
   694             posInBuf+= KSizeOfFatDirEntry;
       
   695             DirWriteL(startPos, TPtrC8(&scratchBuf[0], posInBuf));
       
   696             break;
       
   697             }
       
   698     
       
   699         }//for(;;)
       
   700     }
       
   701 
       
   702 
       
   703 
       
   704 //---------------------------------------------------------------------------------
       
   705 
       
   706 void CFatMountCB::DoEraseEntrySetChunkL(const TEntrySetChunkInfo& aEntrySetChunk)
       
   707     {
       
   708 
       
   709     //-- scratch buffer for whole VFAT entryset. Max number of entries in it is 21 entry or 672 bytes. 
       
   710     //-- in the worst case the entryset can span across 3 clusters (512 bytes per cluster)
       
   711     //-- Using the scratch buffer is not ideal, but write-back directory cache isn't in place yet
       
   712 
       
   713     const TUint KBufSize = 680;
       
   714     TBuf8<KBufSize> scratchBuf;
       
   715 
       
   716     TUint numEntries = aEntrySetChunk.iNumEntries;
       
   717 
       
   718     ASSERT(numEntries >0 && numEntries <= KMaxVFatEntries);
       
   719     const TUint32 KChunkLen = numEntries << KSizeOfFatDirEntryLog2;
       
   720 
       
   721     DirReadL(aEntrySetChunk.iEntryPos, KChunkLen, scratchBuf);
       
   722     
       
   723     TInt posInBuf = 0;
   627 	while (numEntries--)
   724 	while (numEntries--)
   628 		{
   725 		{
   629 		vFatEntry.SetVFatEntry(aLongName,KMaxVFatEntryName*numEntries);//	KMaxVFatEntryName=13
   726         TFatDirEntry* pEntry = (TFatDirEntry*)(scratchBuf.Ptr()+posInBuf);
   630 		if(isSameSector)
   727         pEntry->SetErased();
   631 			{
   728         posInBuf += KSizeOfFatDirEntry;
   632 			Mem::Copy(&localBuf[offset],&vFatEntry,KSizeOfFatDirEntry);
       
   633 			offset+=KSizeOfFatDirEntry;
       
   634 			MoveToNextEntryL(aPos);
       
   635 			}
       
   636 		else
       
   637 			{
       
   638 			WriteDirEntryL(aPos,vFatEntry);
       
   639 			MoveToNextEntryL(aPos);
       
   640 			}
       
   641 		}
       
   642 	if(isSameSector)
       
   643 		{
       
   644 		Mem::Copy(&localBuf[offset],&aFatDirEntry,KSizeOfFatDirEntry);
       
   645 		
       
   646         //-- use special interface to access FAT directory file
       
   647         DirWriteL(startPos,TPtrC8(&localBuf[0],dosOffset+KSizeOfFatDirEntry));
       
   648         }
   729         }
       
   730             
       
   731     DirWriteL(aEntrySetChunk.iEntryPos, scratchBuf);
       
   732     }
       
   733 
       
   734 //---------------------------------------------------------------------------------
       
   735 /**
       
   736     Erase whole VFAT entryset. 
       
   737     For Rugged FAT the situation is more complicated: we need firstly delete the DOS entry _atomically_ i.e. if this operation fails,
       
   738     the whole VFAT entryset won't be broken.  Deleting VFAT entries doesn't require the atomic media writes; DOS entry contains necessary
       
   739     information about data stream.
       
   740     
       
   741     @param aPos         position of the entryset start in the directory.
       
   742     @param aFirstEntry  first entry in the entryset, it can be DOS entry
       
   743     
       
   744 */
       
   745 void CFatMountCB::EraseDirEntryL(TEntryPos aPos,const TFatDirEntry& aFirstEntry)
       
   746 	{
       
   747     __PRINT2(_L("CFatMountCB::EraseDirEntryL() cl:%d, offset:%d"), aPos.Cluster(), aPos.Pos());
       
   748 
       
   749     TUint numEntries=0;
       
   750 	if (aFirstEntry.IsVFatEntry())
       
   751         {
       
   752 		numEntries=aFirstEntry.NumFollowing();
       
   753         numEntries++; //-- take into account the last DOS entry
       
   754 		}
       
   755     else
       
   756         {//-- we are deleting a single DOS entry. This is an atomic operation.
       
   757 		EraseDirEntryL(aPos);
       
   758         return;        
       
   759         }
       
   760 
       
   761     ASSERT(numEntries > 1 && numEntries <= KMaxVFatEntries);
       
   762 
       
   763     TEntrySetChunkInfo chunksInfo[TEntrySetChunkInfo::KMaxChunks];
       
   764 
       
   765     //-- 1. check if the entryset fits into a unit of write ganularity. This will be 1 sector for rugged FAT or 1 cluster otherwise
       
   766 
       
   767     TUint32 MaxWriteGranularityLog2;
       
   768     
       
   769     if(IsRuggedFSys())
       
   770         {
       
   771         MaxWriteGranularityLog2 = AtomicWriteGranularityLog2();
       
   772         }
       
   773     else if(IsRootDir(aPos))
       
   774         {//-- root dir. for FAT12/16 is a special case, it is not made of clusters. it's unit is 1 sector.
       
   775         MaxWriteGranularityLog2 = KDefSectorSzLog2;
       
   776         }
       
   777     else
       
   778         {//-- minimal unit size will be a cluster
       
   779         MaxWriteGranularityLog2 = ClusterSizeLog2();
       
   780         }
       
   781     
       
   782 
       
   783         {
       
   784         const TUint64 KEntrySetStartPos = MakeLinAddrL(aPos);
       
   785         const TUint64 KEntrySetLogicalEndPos = KEntrySetStartPos + (numEntries << KSizeOfFatDirEntryLog2);
       
   786  
       
   787         const TUint64 KBlockEndPos = ((KEntrySetLogicalEndPos-1) >> MaxWriteGranularityLog2) << MaxWriteGranularityLog2;
       
   788         const TUint64 KBlockStartPos = (KEntrySetStartPos >> MaxWriteGranularityLog2) << MaxWriteGranularityLog2;
       
   789         
       
   790         if(KBlockEndPos == KBlockStartPos)
       
   791             {//-- whole entryet is in the same block; the whole entryset erase operation will be atomic for Rugged/non-rugged FAT
       
   792             chunksInfo[0].iEntryPos = aPos;
       
   793             chunksInfo[0].iNumEntries = numEntries;
       
   794             DoEraseEntrySetChunkL(chunksInfo[0]);
       
   795             return;
       
   796             }
       
   797 
       
   798         }
       
   799 
       
   800     //-- the entryset is split on max. 3 parts between units of write granularity (see MaxWriteGranularityLog2).
       
   801     ASSERT(numEntries > 1 && numEntries <= KMaxVFatEntries);
       
   802 
       
   803     TInt cntChunk = 1; //-- there is at least 1 entries chunk
       
   804     TEntrySetChunkInfo* pChunkInfo = chunksInfo;
       
   805 
       
   806     //-- collect information about dir. entry chunks that reside in different units of write granularity
       
   807     for(;;)
       
   808         {
       
   809         TBool movedUnit = EFalse;
       
   810 
       
   811         pChunkInfo->iEntryPos   = aPos;
       
   812         pChunkInfo->iNumEntries = 0;
       
   813         
       
   814         const TUint64 KChunkStartPos = MakeLinAddrL(aPos);
       
   815         const TUint64 KChunkBlockStartPos = (KChunkStartPos >> MaxWriteGranularityLog2) << MaxWriteGranularityLog2;
       
   816         const TUint64 KChunkBlockEndPos   = (KChunkBlockStartPos-1) + (1<<MaxWriteGranularityLog2);
       
   817 
       
   818         while(numEntries)
       
   819             {
       
   820             pChunkInfo->iNumEntries++;
       
   821 		MoveToNextEntryL(aPos);
       
   822             
       
   823             numEntries--;
       
   824             const TUint64 currPos = MakeLinAddrL(aPos);
       
   825             movedUnit = !(currPos >= KChunkBlockStartPos && currPos <= KChunkBlockEndPos); 
       
   826 
       
   827             if(!numEntries || movedUnit)
       
   828                 {
       
   829                 break; 
       
   830                 }
       
   831 
       
   832             }
       
   833 
       
   834         if(movedUnit && numEntries)
       
   835             {//-- move to the next unit of write granularity
       
   836             ++pChunkInfo;
       
   837             ++cntChunk;
       
   838             ASSERT(cntChunk <= TEntrySetChunkInfo::KMaxChunks);
       
   839             continue;
       
   840             }    
       
   841 
       
   842         
       
   843         ASSERT(!numEntries);
       
   844         break;
       
   845         }
       
   846 
       
   847     //-- now do bulk deletion, write data based on collected entries chunks.
       
   848     ASSERT(cntChunk > 0);
       
   849  
       
   850     //-- if it is a rugged FAT, we need to delete DOS entry first; it will be in the last chunk.
       
   851     if(IsRuggedFSys())
       
   852         {
       
   853         const TInt dosEntryChunk = cntChunk-1;
       
   854         DoEraseEntrySetChunkL(chunksInfo[dosEntryChunk]);
       
   855         cntChunk--;
       
   856         }
       
   857 
       
   858     //-- it is also possible to joint entryset chunks together here if they belong to the same cluster. 
       
   859     //-- the atomic write here is not required. 
       
   860 
       
   861     //-- erase the rest of entries in reamining chunks.
       
   862     for(TInt i=0; i<cntChunk; ++i)
       
   863         {
       
   864         DoEraseEntrySetChunkL(chunksInfo[i]);
       
   865         }
       
   866 
       
   867 }
       
   868 
       
   869 //---------------------------------------------------------------------------------
       
   870 /**
       
   871     Convert the volume label using the algorithm specified in the current locale-DLL.
       
   872 */
       
   873 void  LocaleUtils::ConvertFromUnicodeL(TDes8& aForeign, const TDesC16& aUnicode, TFatUtilityFunctions::TOverflowAction aOverflowAction)
       
   874 	{
       
   875 	if(aOverflowAction == TFatUtilityFunctions::EOverflowActionLeave)
       
   876 		{
       
   877 		GetCodePage().ConvertFromUnicodeL(aForeign, aUnicode, TCodePageUtils::EOverflowActionLeave);
       
   878 		}
   649 	else
   879 	else
   650 		WriteDirEntryL(aPos,aFatDirEntry);
   880 		{
   651 	}
   881 		GetCodePage().ConvertFromUnicodeL(aForeign, aUnicode, TCodePageUtils::EOverflowActionTruncate);
   652 
   882 		}
   653 void CFatMountCB::EraseDirEntryL(TEntryPos aPos,const TFatDirEntry& aFirstEntry)
   883 	}
   654 //
   884 //---------------------------------------------------------------------------------
   655 // Mark all entries in a VFat directory entry as erased
   885 /**
   656 //
   886     Convert the volume label using the algorithm specified in the current locale-DLL.
   657 	{
   887 */
   658 	__PRINT(_L("VFAT::CFatMountCB::EraseDirEntryL"));
   888 void  LocaleUtils::ConvertToUnicodeL(TDes16& aUnicode, const TDesC8& aForeign, TFatUtilityFunctions::TOverflowAction aOverflowAction)
   659 	TInt numEntries=0;
       
   660 	if (aFirstEntry.IsVFatEntry())
       
   661 		numEntries=aFirstEntry.NumFollowing();
       
   662 	if(IsRuggedFSys()&&numEntries)
       
   663 		{
       
   664 		TInt count=numEntries;
       
   665 		TEntryPos pos=aPos;
       
   666 		while(count--)
       
   667 			MoveToNextEntryL(pos);
       
   668 		EraseDirEntryL(pos);
       
   669 		numEntries--;
       
   670 		}
       
   671 	FOREVER
       
   672 		{
       
   673 		EraseDirEntryL(aPos);
       
   674 		if (!numEntries--)
       
   675 			break;
       
   676 		MoveToNextEntryL(aPos);
       
   677 		}
       
   678 	}
       
   679 
       
   680 
       
   681 void  LocaleUtils::ConvertFromUnicodeL(TDes8& aForeign, const TDesC16& aUnicode, TFatUtilityFunctions::TOverflowAction aOverflowAction)
       
   682 //
       
   683 // Convert the volume label using the algorithm specified in the current locale-DLL.
       
   684 //
       
   685 	{
   889 	{
   686 	if(aOverflowAction == TFatUtilityFunctions::EOverflowActionLeave)
   890 	if(aOverflowAction == TFatUtilityFunctions::EOverflowActionLeave)
   687 		{
   891 		{
   688 		GetCodePage().ConvertFromUnicodeL(aForeign, aUnicode, TCodePageUtils::EOverflowActionLeave);
   892 		GetCodePage().ConvertToUnicodeL(aUnicode, aForeign, TCodePageUtils::EOverflowActionLeave);
   689 		}
   893 		}
   690 	else
   894 	else
   691 		{
   895 		{
   692 		GetCodePage().ConvertFromUnicodeL(aForeign, aUnicode, TCodePageUtils::EOverflowActionTruncate);
       
   693 		}
       
   694 	}
       
   695 
       
   696 void  LocaleUtils::ConvertToUnicodeL(TDes16& aUnicode, const TDesC8& aForeign, TFatUtilityFunctions::TOverflowAction aOverflowAction)
       
   697 //
       
   698 // Convert the volume label using the algorithm specified in the current locale-DLL.
       
   699 //
       
   700 	{
       
   701 	if(aOverflowAction == TFatUtilityFunctions::EOverflowActionLeave)
       
   702 		{
       
   703 		GetCodePage().ConvertToUnicodeL(aUnicode, aForeign, TCodePageUtils::EOverflowActionLeave);
       
   704 		}
       
   705 	else
       
   706 		{
       
   707 		GetCodePage().ConvertToUnicodeL(aUnicode, aForeign, TCodePageUtils::EOverflowActionTruncate);
   896 		GetCodePage().ConvertToUnicodeL(aUnicode, aForeign, TCodePageUtils::EOverflowActionTruncate);
   708 		}
   897 		}
   709 	}
   898 	}
   710 
   899 
       
   900 //---------------------------------------------------------------------------------
       
   901 /**
       
   902     Convert the volume label using the algorithm specified in the current locale-DLL.
       
   903 */
   711 TBool LocaleUtils::IsLegalShortNameCharacter(TUint aCharacter,TBool aUseExtendedChars)
   904 TBool LocaleUtils::IsLegalShortNameCharacter(TUint aCharacter,TBool aUseExtendedChars)
   712 //
       
   713 // Convert the volume label using the algorithm specified in the current locale-DLL.
       
   714 //
       
   715 	{
   905 	{
   716 	return GetCodePage().IsLegalShortNameCharacter(aCharacter, aUseExtendedChars);
   906 	return GetCodePage().IsLegalShortNameCharacter(aCharacter, aUseExtendedChars);
   717 	}
   907 	}
       
   908 
       
   909 
       
   910 
       
   911 
       
   912 
       
   913 
       
   914 
       
   915 
       
   916