userlibandfileserver/fileserver/sfat32/sl_vfat.cpp
changeset 15 4122176ea935
child 62 4a8fed1c0ef6
child 90 947f0dc9f7a8
equal deleted inserted replaced
0:a41df078684a 15:4122176ea935
       
     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\sl_vfat.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "sl_std.h"
       
    19 #include "sl_cache.h"
       
    20 #include <e32svr.h>
       
    21 #include <e32math.h>
       
    22 
       
    23 
       
    24 IMPORT_C const TFatUtilityFunctions* GetFatUtilityFunctions();
       
    25 
       
    26 const TInt KMaxLengthWithoutTilde = 8;
       
    27 const TUint8 KLeadingE5Replacement = 0x05;
       
    28 
       
    29 // use second half of ISO Latin 1 character set for extended chars
       
    30 const TUint KExtendedCharStart=0x80;
       
    31 const TUint KExtendedCharEnd=0xff;
       
    32 
       
    33 LOCAL_C TBool IsLegalChar(TChar aCharacter,TBool aAllowWildChars,TBool aUseExtendedChars=EFalse,TBool aInScanDrive=EFalse)
       
    34 //
       
    35 // Returns ETrue if aCharacter is legal inside a dos filename
       
    36 //
       
    37 	{
       
    38 	if ((aCharacter==KMatchOne) || (aCharacter==KMatchAny))
       
    39 		return(aAllowWildChars);
       
    40 	if ((TUint)aCharacter < 0x20)
       
    41 	    return EFalse;
       
    42    	// Don't check illegal ascii char because some non-English char value may
       
    43    	// fall in this area
       
    44     if (aInScanDrive)
       
    45     	return ETrue;
       
    46 	return LocaleUtils::IsLegalShortNameCharacter(aCharacter,aUseExtendedChars);
       
    47 	}
       
    48 
       
    49 LOCAL_C void ReplaceFirstCharacterIfClashesWithE5L(TDes8& aShortName)
       
    50 	{
       
    51 	if (0 < aShortName.Length() && aShortName[0] == KEntryErasedMarker)
       
    52 		{
       
    53 		aShortName[0] = KLeadingE5Replacement;
       
    54 		}
       
    55 	}
       
    56 
       
    57 LOCAL_C void ReplaceIllegalCharactersL(TDes& aLongName, TUint aCharacterToReplaceWith)
       
    58 	{
       
    59 	TBool alreadyFoundExtensionDelimiter=EFalse;
       
    60 
       
    61 	TInt LongNameLen = aLongName.Length();
       
    62 	TInt extDelimiterIndex = aLongName.LocateReverse(KExtDelimiter);
       
    63 
       
    64 	for (TInt i=LongNameLen-1; i>=0; --i) // iterate backwards as aLongName may change length during the loop, and also because we want to leave the *right-most* occurrence of KExtDelimiter unchanged
       
    65 		{
       
    66 		TUint character=aLongName[i];
       
    67 		if (character==(TUint)KExtDelimiter)
       
    68 			{
       
    69 			if (alreadyFoundExtensionDelimiter)
       
    70 				{
       
    71 				aLongName[i]=(TText)aCharacterToReplaceWith; // A.B.C becomes A_B.C
       
    72 				}
       
    73 			alreadyFoundExtensionDelimiter=ETrue;
       
    74 			}
       
    75 		else
       
    76 			{
       
    77 			// the code below doesn't need any #if defined(_UNICODE) stuff as a narrow-build aLongName would not contain values above 0xff (which is well below the surrogates area in Unicode 0xd800-0xdfff)
       
    78 			TBool isSurrogatePair=EFalse;
       
    79 
       
    80 			// LAST character in file name or file ext CAN NOT be HIGH surrogate
       
    81 			if (i==LongNameLen-1 || i==extDelimiterIndex-1)
       
    82 				{
       
    83 				if (IsHighSurrogate((TText16)character))
       
    84 					{
       
    85 					// Corrupt surrogate
       
    86 					User::Leave(KErrBadName);
       
    87 					}
       
    88 				}
       
    89 			// FIRST character in file name or file ext CAN NOT be LOW surrogate
       
    90 			if (i==0 || i==extDelimiterIndex+1)
       
    91 				{
       
    92 				if (IsLowSurrogate((TText16)character))
       
    93 					{
       
    94 					// Corrupt surrogate
       
    95 					User::Leave(KErrBadName);
       
    96 					}
       
    97 				}
       
    98 			// if LOW Surrogate
       
    99 			if (IsLowSurrogate((TText16)character))
       
   100 				{
       
   101 				// check for HIGH surrogate
       
   102 				if (!IsHighSurrogate(aLongName[--i]))
       
   103 					{
       
   104 					// Corrupt surrogate
       
   105 					User::Leave(KErrBadName);
       
   106 					}
       
   107 				// surrogate pair found
       
   108 				character&=~0xdc00;
       
   109 				character|=((aLongName[i]&~0xd800)<<10);
       
   110 				character+=0x00010000; // this must be added - it cannot be bitwise-"or"-ed
       
   111 				isSurrogatePair=ETrue;
       
   112 				}
       
   113 
       
   114 			// if High Surrogate
       
   115 			if (!isSurrogatePair && IsHighSurrogate((TText16)character))
       
   116 				{
       
   117 				// Corrupt surrogate
       
   118 				User::Leave(KErrBadName);
       
   119 				}
       
   120 
       
   121 			if (!IsLegalChar(character, EFalse))
       
   122 				{
       
   123 				if (isSurrogatePair)
       
   124 					{
       
   125 					aLongName.Delete(i+1, 1);
       
   126 					}
       
   127 				aLongName[i]=(TText)aCharacterToReplaceWith;
       
   128 				}
       
   129 			}
       
   130 		}
       
   131 	}
       
   132 
       
   133 TShortName DoGenerateShortNameL(const TDesC& aLongName,TInt& aNum,TBool aUseTildeSelectively)
       
   134 //
       
   135 // Create a legal shortname from aLongName
       
   136 //
       
   137 	{
       
   138 
       
   139 	TFileName longName(aLongName);
       
   140 	longName.UpperCase();
       
   141 	ReplaceIllegalCharactersL(longName, '_');
       
   142 	TPtrC longNameWithoutExtension(longName);
       
   143 	TPtrC longNameExtension(KNullDesC);
       
   144 	const TInt positionOfExtension=longName.LocateReverse(KExtDelimiter);
       
   145 	if (positionOfExtension==0)
       
   146 		{
       
   147 		// No filename specified, so use the extension as the basis of the shortname.
       
   148 		// Make sure we always append a tilde+number in this case to avoid generating the same 
       
   149 		// short filename as one of the protected folders ("\SYS", "\RESOURCE","\PRIVATE")
       
   150 		longNameWithoutExtension.Set(longName.Mid(positionOfExtension+1));
       
   151 		aUseTildeSelectively = EFalse;
       
   152 		if (aNum < 0)
       
   153 			aNum = 1;
       
   154 		}
       
   155 	else if (positionOfExtension!=KErrNotFound)
       
   156 		{
       
   157 		longNameWithoutExtension.Set(longName.Left(positionOfExtension));
       
   158 		longNameExtension.Set(longName.Mid(positionOfExtension+1));
       
   159 		}
       
   160 	
       
   161 	// Converts the original file name main part into 8-bit character string
       
   162 	TShortName tempShortName(0);
       
   163 
       
   164 	LocaleUtils::ConvertFromUnicodeL(tempShortName, longNameWithoutExtension);
       
   165 	const TInt originalNameLength = tempShortName.Length();
       
   166 
       
   167 	// Converts the original file name extension part into 8-bit character string
       
   168 	TShortName tempShortNameExt(0);
       
   169 	
       
   170 	LocaleUtils::ConvertFromUnicodeL(tempShortNameExt, longNameExtension);
       
   171 	const TInt extensionNameLength = tempShortNameExt.Length();
       
   172 	// // const TInt extensionNameLength = tempShortNameExt.Length();
       
   173 
       
   174 	// Checks the length of both original file name main part and original file name extension part
       
   175 	if(aUseTildeSelectively)
       
   176 		{
       
   177 		// don't append ~<aNum>
       
   178 		if(originalNameLength<=KMaxLengthWithoutTilde && extensionNameLength<=KMaxFatFileNameExt)
       
   179 			aNum=-1;
       
   180 		}
       
   181 
       
   182 	// Applies tilde and number if necessary
       
   183 	TBuf8<5> tildeAndNumber;
       
   184 	if (aNum>=0)
       
   185 		{
       
   186 		tildeAndNumber.Append('~');
       
   187 		tildeAndNumber.AppendNumUC(aNum,EHex);
       
   188 		}
       
   189 	const TInt lengthOfTildeAndNumber=tildeAndNumber.Length();
       
   190 
       
   191 	// Creates actual shortname from longname of the original file
       
   192 	TShortName shortName(11);
       
   193 #if defined(_DEBUG)
       
   194 	shortName.Fill(0x01); // fill shortName with garbage to ensure that every byte is written to by this function
       
   195 #endif
       
   196 
       
   197 	// Fills the main part of the shortname of the original file
       
   198 	const TInt numberOfBytesFreeBeforeTilde=KMaxFatFileNameWithoutExt-lengthOfTildeAndNumber;
       
   199 
       
   200 	TPtr8 portionOfShortNameBeforeTilde((TUint8*)shortName.Ptr(), 0, numberOfBytesFreeBeforeTilde);
       
   201 	TInt lengthOfPortionOfShortNameBeforeTilde = 
       
   202 				(originalNameLength < numberOfBytesFreeBeforeTilde) ? originalNameLength : numberOfBytesFreeBeforeTilde;
       
   203 
       
   204 	portionOfShortNameBeforeTilde.Copy((TUint8*)tempShortName.Ptr(), lengthOfPortionOfShortNameBeforeTilde);
       
   205 	if( lengthOfPortionOfShortNameBeforeTilde != originalNameLength)
       
   206 		{
       
   207 		for( int i = 0; i<lengthOfPortionOfShortNameBeforeTilde; i++)
       
   208 			{
       
   209 			if(portionOfShortNameBeforeTilde[i] >= 0x80) //leading byte found
       
   210 				{
       
   211 				if( i == lengthOfPortionOfShortNameBeforeTilde - 1) //leading byte found on the edge
       
   212 					{
       
   213 					lengthOfPortionOfShortNameBeforeTilde -= 1;
       
   214 					break;
       
   215 					}
       
   216 				else
       
   217 					{
       
   218 					i++;
       
   219 					}
       
   220 				}
       
   221 			}
       
   222 		}
       
   223 	Mem::Copy(((TUint8*)shortName.Ptr())+lengthOfPortionOfShortNameBeforeTilde, tildeAndNumber.Ptr(), lengthOfTildeAndNumber);
       
   224 	TInt i;
       
   225 	for (i=lengthOfPortionOfShortNameBeforeTilde+lengthOfTildeAndNumber; i<KMaxFatFileNameWithoutExt; ++i)
       
   226 		{
       
   227 		shortName[i]=' ';
       
   228 		}
       
   229 
       
   230 	// Fills the extension part of the shortname of the original file
       
   231 	TInt lengthOfExt = 
       
   232 				(extensionNameLength < KMaxFatFileNameExt) ? extensionNameLength : KMaxFatFileNameExt;
       
   233 	
       
   234 	if( lengthOfExt != extensionNameLength)
       
   235 		{
       
   236 		for( int i = 0; i<lengthOfExt; i++)
       
   237 			{
       
   238 			if(tempShortNameExt[i] >= 0x80)
       
   239 				{
       
   240 				if( i == lengthOfExt - 1)
       
   241 					{
       
   242 					lengthOfExt -= 1;
       
   243 					break;
       
   244 					}
       
   245 				else
       
   246 					{
       
   247 					i++;
       
   248 					}
       
   249 				}
       
   250 			}
       
   251 		}			
       
   252 	Mem::Copy(((TUint8*)shortName.Ptr()) + KMaxFatFileNameWithoutExt, tempShortNameExt.Ptr(), lengthOfExt);
       
   253 	for (i = KMaxFatFileNameWithoutExt + lengthOfExt; i<KMaxFatFileNameWithoutExt+KMaxFatFileNameExt; ++i)
       
   254 		{
       
   255 		shortName[i]=' ';
       
   256 		}
       
   257 	
       
   258 	ReplaceFirstCharacterIfClashesWithE5L(shortName);		
       
   259 	return shortName;
       
   260 	}
       
   261 
       
   262 
       
   263 /**
       
   264 Check whether a Dos name is legal or not.
       
   265 
       
   266 @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
       
   268 @param aUseExtendedChars    Flag to indicate if extended characters are allowed
       
   269 @param aInScanDrive         Flag to indicate whether called when scanning drive
       
   270 @param aAllowLowerCase      ETrue to allow lower case in the analysed DOS name
       
   271 
       
   272 @return ETrue if the name is a legal DOS one.
       
   273 */
       
   274 
       
   275 static TBool DoCheckLegalDosName(const TDesC& aName, TBool anAllowWildCards, TBool aUseExtendedChars, TBool aInScanDrive, TBool aAllowLowerCase, TBool aIsForFileCreation)
       
   276 	{
       
   277     const TInt count=aName.Length();
       
   278 	if (count==0)
       
   279 		return EFalse;
       
   280 
       
   281 	TInt valid=0;
       
   282 	TInt i=0;
       
   283 	
       
   284     //-- check the entry name
       
   285 	while (i<count)
       
   286 		{
       
   287 		TChar c=aName[i++];
       
   288 		if (c==KExtDelimiter)
       
   289 			{
       
   290 			// DOS entry names must contain at least one valid character before the extension
       
   291 			if (i == 1)
       
   292 				return EFalse;
       
   293 			break;
       
   294 			}
       
   295 		
       
   296           if(!aAllowLowerCase && c.IsLower())
       
   297             return EFalse; //-- low case is not allowed
       
   298 
       
   299 		if (!IsLegalChar(c,anAllowWildCards,aUseExtendedChars,aInScanDrive))
       
   300 		    {
       
   301 			return EFalse;
       
   302 		    }
       
   303 		
       
   304 		if (aIsForFileCreation)
       
   305 			{
       
   306 			if ((aUseExtendedChars && (TUint) c > KExtendedCharEnd) || 
       
   307 					(!aUseExtendedChars && (TUint) c > KExtendedCharStart))
       
   308 				{
       
   309 				return EFalse;
       
   310 				}
       
   311 			}
       
   312 
       
   313 		if (c!=KMatchAny)
       
   314 			if (++valid>KMaxFatFileNameWithoutExt)
       
   315 				return EFalse;
       
   316 		}
       
   317 	
       
   318 	//-- check entry extension
       
   319     valid=0;
       
   320 	while (i<count)
       
   321 		{
       
   322 		TChar c=aName[i++];
       
   323 		if (c==KExtDelimiter)
       
   324 			return EFalse;
       
   325 		
       
   326         if(!aAllowLowerCase && c.IsLower())
       
   327             return EFalse; //-- low case is not allowed
       
   328 
       
   329 		if (!IsLegalChar(c,anAllowWildCards,aUseExtendedChars,aInScanDrive))
       
   330 			return EFalse;
       
   331 		
       
   332 		if (aIsForFileCreation)
       
   333 			{
       
   334 			if ((aUseExtendedChars && (TUint) c > KExtendedCharEnd) || 
       
   335 					(!aUseExtendedChars && (TUint) c > KExtendedCharStart))
       
   336 				{
       
   337 				return EFalse;
       
   338 				}
       
   339 			}
       
   340 
       
   341 		if (c!=KMatchAny)
       
   342 			if (++valid>KMaxFatFileNameExt)
       
   343 				return EFalse;
       
   344 		}
       
   345 	
       
   346 	// Unicode file name checking for file opening.
       
   347 	if (!aIsForFileCreation && GetFatUtilityFunctions())
       
   348 		{
       
   349 		TBuf8<KMaxFileName*2> convertedName8;
       
   350 		TRAPD(err, LocaleUtils::ConvertFromUnicodeL(convertedName8, aName, TFatUtilityFunctions::EOverflowActionLeave));
       
   351 		if (err != KErrNone)
       
   352 			return EFalse;
       
   353 		
       
   354 		const TInt len8 = convertedName8.Length();
       
   355 		TInt j = 0; 
       
   356 		TInt nonWildChar = 0;
       
   357 		while (j < len8)
       
   358 			{
       
   359 			const TUint8 c8 = convertedName8[j++];
       
   360 			if (c8 == KExtDelimiter)
       
   361 				break;
       
   362 			if (c8 == '*' && !anAllowWildCards)
       
   363 				return EFalse;
       
   364 			if (c8 == '*' && anAllowWildCards)
       
   365 				continue;
       
   366 			
       
   367 			if (++nonWildChar > KMaxFatFileNameWithoutExt)
       
   368 				return EFalse;
       
   369 			}
       
   370 		
       
   371 		// check extension part
       
   372 		nonWildChar = 0;
       
   373 		while (j < len8)
       
   374 			{
       
   375 			const TUint8 c8 = convertedName8[j++];
       
   376 			if (c8 == KExtDelimiter)
       
   377 				return EFalse;
       
   378 			if (c8 == '*' && !anAllowWildCards)
       
   379 				return EFalse;
       
   380 			if (c8 == '*' && anAllowWildCards)
       
   381 				continue;
       
   382 			
       
   383 			if (++nonWildChar > KMaxFatFileNameExt)
       
   384 				return EFalse;
       
   385 			}
       
   386 		}
       
   387 
       
   388 	return ETrue;
       
   389 	}
       
   390 
       
   391 /**
       
   392     Check whether a Dos name is legal or not. Unicode version
       
   393     parameters and return value absolutely the same as in DoCheckLegalDosName()
       
   394 */
       
   395 TBool IsLegalDosName(const TDesC16& aName, TBool anAllowWildCards, TBool aUseExtendedChars, TBool aInScanDrive, TBool aAllowLowerCase, TBool aIsForFileCreation)
       
   396 	{
       
   397 
       
   398 	__PRINT(_L("IsLegalDosName 16"));
       
   399 
       
   400     return DoCheckLegalDosName(aName, anAllowWildCards, aUseExtendedChars, aInScanDrive, aAllowLowerCase, aIsForFileCreation);	
       
   401 	}
       
   402 
       
   403 TBool CFatMountCB::FindShortNameL(const TShortName& aName,TEntryPos& anEntryPos)
       
   404 //
       
   405 // Returns ETrue and the entryPos of aName if found or EFalse
       
   406 //
       
   407 	{
       
   408 	
       
   409 	__PRINT(_L("VFAT::CFatMountCB::FindShortNameL"));	
       
   410 	TFatDirEntry fatEntry;
       
   411 	TInt count=0;
       
   412 	FOREVER
       
   413 		{
       
   414 		count++;
       
   415 		ReadDirEntryL(anEntryPos,fatEntry);
       
   416 		MoveToDosEntryL(anEntryPos,fatEntry);
       
   417 		if (fatEntry.IsEndOfDirectory())
       
   418 			break;
       
   419 		if (IsRootDir(anEntryPos)&&(anEntryPos.iPos+StartOfRootDirInBytes()==(RootDirEnd()-KSizeOfFatDirEntry)))	
       
   420 			if (fatEntry.IsErased())
       
   421 				break;//Allows maximum number of entries in root directory
       
   422 		if (fatEntry.Name()==aName)
       
   423 			return ETrue;
       
   424 		MoveToNextEntryL(anEntryPos);
       
   425 		if (IsRootDir(anEntryPos)&&(StartOfRootDirInBytes()+anEntryPos.iPos==RootDirEnd()))
       
   426 			break;//Allows maximum number of entries in root directory
       
   427 		}
       
   428 	return EFalse;
       
   429 	}
       
   430 	
       
   431 TBool CFatMountCB::IsUniqueNameL(const TShortName& aName,TInt aDirCluster)
       
   432 //
       
   433 // Returns ETrue if aName is unique, EFalse if a matching name is found.
       
   434 //
       
   435 	{
       
   436 
       
   437 	__PRINT(_L("VFAT::CFatMountCB::IsUniqueNameL"));	
       
   438 	TEntryPos entryPos(aDirCluster,0);
       
   439 	if (FindShortNameL(aName,entryPos))
       
   440 		return(EFalse);
       
   441 	return(ETrue);
       
   442 	}
       
   443 
       
   444 void CFatMountCB::ReplaceClashingNameL(const TShortName& aNewName,const TEntryPos& anEntryPos)
       
   445 //
       
   446 // A legal dos name has been typed that clashes with a computer generated shortname
       
   447 // Change the shortname to something else.
       
   448 //
       
   449 	{
       
   450 
       
   451 	__PRINT(_L("VFAT::CFatMountCB::ReplaceClashingNameL"));	
       
   452 	TFatDirEntry entry;
       
   453 	ReadDirEntryL(anEntryPos,entry);
       
   454 	__ASSERT_ALWAYS(entry.IsEndOfDirectory()==EFalse,User::Leave(KErrCorrupt));
       
   455 	entry.SetName(aNewName);
       
   456 	WriteDirEntryL(anEntryPos,entry);
       
   457 //	We now need to fix up VFAT entries with a new checksum reflecting new shortname
       
   458 //	Calculate new checksum
       
   459 	TUint8 checksum=CalculateShortNameCheckSum(aNewName);
       
   460 //	Now go back and adjust all VFAT entries corresponding to this shortname
       
   461 	TEntryPos entryPos=anEntryPos;
       
   462 	FOREVER
       
   463 		{
       
   464 		entryPos.iPos-=KSizeOfFatDirEntry;	
       
   465 		ReadDirEntryL(entryPos,entry);
       
   466 		entry.iData[0x0D]=checksum;
       
   467 		if (entry.iData[0]&0x40)
       
   468 			break;
       
   469 		}
       
   470 	}
       
   471 
       
   472 TBool CFatMountCB::GenerateShortNameL(TInt aDirCluster,const TDesC& aName,TShortName& aGeneratedName, TBool aForceRandomize)
       
   473 //
       
   474 // Generate a legal dos filename as an alias for aName.
       
   475 // Returns ETrue if aName is a legal dos name.
       
   476 //
       
   477 	{
       
   478 
       
   479 	__PRINT(_L("VFAT::CFatMountCB::GenerateShortNameL"));
       
   480 	// Given the long file-name "ABCDEFGHI.TXT", EPOC used to generate short 
       
   481 	// file-names in the following pecking order:
       
   482 	//     "ABCDEFGH.TXT",
       
   483 	//     "ABCDEF~0.TXT",
       
   484 	//     "ABCDEF~1.TXT",
       
   485 	//     "ABCDEF~2.TXT",
       
   486 	//     etc.
       
   487 	// Now, however, EPOC behaves in a more Windows-like manner and 
       
   488 	// generates short file-names in this pecking order:
       
   489 	//     "ABCDEF~1.TXT",
       
   490 	//     "ABCDEF~2.TXT",
       
   491 	//     "ABCDEF~3.TXT",
       
   492 	//     "ABCDEF~4.TXT",
       
   493 	// After failing to find an unused short name 4 times in a row, 
       
   494 	// a random number is used to speed up the process. So subsequent
       
   495 	// short-file names become
       
   496 	//     "ABC~nnnn.TXT"	where nnnn is a random number
       
   497 	//    
       
   498 	TBool useTildeSelectively = ETrue;
       
   499 	TInt endNum = KMaxDuplicateShortName;	//	0xFFFF
       
   500 	const TInt KMaxNonRandomShortFileNames = 4;
       
   501 
       
   502 	TInt i = 1;
       
   503 
       
   504 	TBool randomize = aForceRandomize;
       
   505 	if (randomize)
       
   506 		{
       
   507 		i = (TInt) (Math::Random() & KMaxDuplicateShortName);
       
   508 		endNum = (i - 1) & KMaxDuplicateShortName;
       
   509 		}
       
   510 
       
   511 	while(i != endNum)
       
   512 		{
       
   513 		aGeneratedName=DoGenerateShortNameL(aName,i,useTildeSelectively);
       
   514 
       
   515 		if (IsUniqueNameL(aGeneratedName,aDirCluster))
       
   516 			break;
       
   517 
       
   518 		if (i == KMaxNonRandomShortFileNames && !randomize)
       
   519 			{
       
   520 			randomize = ETrue;
       
   521 			i = (TInt) (Math::Random() & KMaxDuplicateShortName);
       
   522 			endNum = (i - 1) & KMaxDuplicateShortName;
       
   523 			}
       
   524 		else if (i == -1)
       
   525 			{
       
   526 			useTildeSelectively=EFalse;
       
   527 			i = 1;
       
   528 			}
       
   529 		else
       
   530 			i = (i + 1) & KMaxDuplicateShortName;
       
   531 		}
       
   532 
       
   533 	if (i == endNum)
       
   534 		User::Leave(KErrAlreadyExists);
       
   535 
       
   536 	if((i == -1) && IsLegalDosName(aName,EFalse,EFalse,EFalse,EFalse,ETrue))
       
   537 		{
       
   538 		// Original file name is a legal 8.3 name
       
   539 		return(ETrue);
       
   540 		}
       
   541 	else
       
   542 		{
       
   543 	    return(EFalse);
       
   544 		}
       
   545 
       
   546 
       
   547 	}
       
   548 
       
   549 void TFatDirEntry::InitializeAsVFat(TUint8 aCheckSum)
       
   550 //
       
   551 // Initialize a FAT entry as a VFAT filename
       
   552 //
       
   553 	{
       
   554 
       
   555 	Mem::Fill(this,sizeof(SFatDirEntry),0xFF);
       
   556 	iData[0x0B]=0x0F;
       
   557 	iData[0x0C]=0x00; iData[0x0D]=aCheckSum;
       
   558 	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 
       
   567 	TInt rem=aName.Length()-aLen;
       
   568 	TPtrC section(aName.Ptr()+aLen,Min(rem,KMaxVFatEntryName));
       
   569 	TBuf16<KMaxVFatEntryName> buf16;
       
   570 	buf16.Copy(section);
       
   571 	if (rem<KMaxVFatEntryName)
       
   572 		{
       
   573 		rem++;
       
   574 		buf16.ZeroTerminate();
       
   575 		buf16.SetLength(rem); // Zero termination doesn't increase the buf length
       
   576 		}
       
   577 	TUint8 orderNo=(TUint8)(aLen/KMaxVFatEntryName+1);
       
   578 	TInt s=Min(rem,5);
       
   579 	Mem::Copy(&iData[0x01],buf16.Ptr(),s*2);//Copy up to 10 bytes of buf16 into iData
       
   580 	TInt offset=s;
       
   581 	rem-=s;
       
   582 	s=Min(rem,6);
       
   583 	Mem::Copy(&iData[0x0E],buf16.Ptr()+offset,s*2);
       
   584 	offset+=s;
       
   585 	rem-=s;
       
   586 	s=Min(rem,2);
       
   587 	Mem::Copy(&iData[0x1C],buf16.Ptr()+offset,s*2);
       
   588 	rem-=s;
       
   589 	if (rem==0)
       
   590 		orderNo|=0x40;
       
   591 	iData[0]=orderNo;
       
   592 	}
       
   593 
       
   594 void TFatDirEntry::ReadVFatEntry(TDes16& aBuf) const
       
   595 //
       
   596 // Read KMaxVFatEntryName unicode chars from the entry
       
   597 //
       
   598 	{
       
   599 
       
   600 	aBuf.SetLength(KMaxVFatEntryName);
       
   601 	Mem::Copy(&aBuf[0],&iData[0x01],5*2);
       
   602 	Mem::Copy(&aBuf[5],&iData[0x0E],6*2);
       
   603 	Mem::Copy(&aBuf[11],&iData[0x1C],2*2);
       
   604 	}
       
   605 
       
   606 void CFatMountCB::WriteDirEntryL(TEntryPos& aPos,const TFatDirEntry& aFatDirEntry,const TDesC& aLongName)
       
   607 //
       
   608 // Write a VFAT directory entry to disk at position aPos - leave aPos refering to the dos entry
       
   609 // Assumes sufficient space has been created for it by AddDirEntry.
       
   610 //
       
   611 	{
       
   612 
       
   613 	__PRINT(_L("VFAT::CFatMountCB::WriteDirEntryL"));	
       
   614 	__ASSERT_DEBUG(aLongName.Length(),Fault(EVFatNoLongName));
       
   615 	TEntryPos startPos(aPos.iCluster,aPos.iPos);
       
   616 	TUint8  localBuf[KDefaultSectorSize];
       
   617 	TUint8 cksum=CalculateShortNameCheckSum(aFatDirEntry.Name());
       
   618 	TInt numEntries=NumberOfVFatEntries(aLongName.Length())-1; // Excluding dos entry
       
   619 	// see if all entries written to one sector
       
   620 	// single sector writes not supported if sector size>default size 
       
   621 	TInt dosOffset=numEntries<<KSizeOfFatDirEntryLog2;
       
   622 	TInt absolutePos=(aPos.iCluster<<ClusterSizeLog2())+ClusterRelativePos(aPos.iPos);
       
   623 	TBool isSameSector=(((absolutePos^(absolutePos+dosOffset))>>SectorSizeLog2())==0 && ((TUint)(1<<SectorSizeLog2())<=KDefaultSectorSize));
       
   624 	TFatDirEntry vFatEntry;
       
   625 	vFatEntry.InitializeAsVFat(cksum);
       
   626 	TInt offset=0;
       
   627 	while (numEntries--)
       
   628 		{
       
   629 		vFatEntry.SetVFatEntry(aLongName,KMaxVFatEntryName*numEntries);//	KMaxVFatEntryName=13
       
   630 		if(isSameSector)
       
   631 			{
       
   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         }
       
   649 	else
       
   650 		WriteDirEntryL(aPos,aFatDirEntry);
       
   651 	}
       
   652 
       
   653 void CFatMountCB::EraseDirEntryL(TEntryPos aPos,const TFatDirEntry& aFirstEntry)
       
   654 //
       
   655 // Mark all entries in a VFat directory entry as erased
       
   656 //
       
   657 	{
       
   658 	__PRINT(_L("VFAT::CFatMountCB::EraseDirEntryL"));
       
   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 	{
       
   686 	if(aOverflowAction == TFatUtilityFunctions::EOverflowActionLeave)
       
   687 		{
       
   688 		GetCodePage().ConvertFromUnicodeL(aForeign, aUnicode, TCodePageUtils::EOverflowActionLeave);
       
   689 		}
       
   690 	else
       
   691 		{
       
   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);
       
   708 		}
       
   709 	}
       
   710 
       
   711 TBool LocaleUtils::IsLegalShortNameCharacter(TUint aCharacter,TBool aUseExtendedChars)
       
   712 //
       
   713 // Convert the volume label using the algorithm specified in the current locale-DLL.
       
   714 //
       
   715 	{
       
   716 	return GetCodePage().IsLegalShortNameCharacter(aCharacter, aUseExtendedChars);
       
   717 	}