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