1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/userlibandfileserver/fileserver/sfat/sl_vfat.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,726 @@
1.4 +// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// f32\sfat\sl_vfat.cpp
1.18 +//
1.19 +//
1.20 +
1.21 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1.22 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1.23 +//!!
1.24 +//!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it
1.25 +//!!
1.26 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1.27 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1.28 +
1.29 +
1.30 +#include "sl_std.h"
1.31 +#include "sl_cache.h"
1.32 +#include <e32svr.h>
1.33 +#include <e32math.h>
1.34 +
1.35 +
1.36 +IMPORT_C const TFatUtilityFunctions* GetFatUtilityFunctions();
1.37 +
1.38 +const TInt KMaxLengthWithoutTilde = 8;
1.39 +const TUint8 KLeadingE5Replacement = 0x05;
1.40 +
1.41 +// use second half of ISO Latin 1 character set for extended chars
1.42 +const TUint KExtendedCharStart=0x80;
1.43 +const TUint KExtendedCharEnd=0xff;
1.44 +
1.45 +LOCAL_C TBool IsLegalChar(TChar aCharacter,TBool aAllowWildChars,TBool aUseExtendedChars=EFalse,TBool aInScanDrive=EFalse)
1.46 +//
1.47 +// Returns ETrue if aCharacter is legal inside a dos filename
1.48 +//
1.49 + {
1.50 + if ((aCharacter==KMatchOne) || (aCharacter==KMatchAny))
1.51 + return(aAllowWildChars);
1.52 + if ((TUint)aCharacter < 0x20)
1.53 + return EFalse;
1.54 + // Don't check illegal ascii char because some non-English char value may
1.55 + // fall in this area
1.56 + if (aInScanDrive)
1.57 + return ETrue;
1.58 + return LocaleUtils::IsLegalShortNameCharacter(aCharacter,aUseExtendedChars);
1.59 + }
1.60 +
1.61 +LOCAL_C void ReplaceFirstCharacterIfClashesWithE5L(TDes8& aShortName)
1.62 + {
1.63 + if (0 < aShortName.Length() && aShortName[0] == KEntryErasedMarker)
1.64 + {
1.65 + aShortName[0] = KLeadingE5Replacement;
1.66 + }
1.67 + }
1.68 +
1.69 +LOCAL_C void ReplaceIllegalCharactersL(TDes& aLongName, TUint aCharacterToReplaceWith)
1.70 + {
1.71 + TBool alreadyFoundExtensionDelimiter=EFalse;
1.72 +
1.73 + TInt LongNameLen = aLongName.Length();
1.74 + TInt extDelimiterIndex = aLongName.LocateReverse(KExtDelimiter);
1.75 +
1.76 + 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
1.77 + {
1.78 + TUint character=aLongName[i];
1.79 + if (character==(TUint)KExtDelimiter)
1.80 + {
1.81 + if (alreadyFoundExtensionDelimiter)
1.82 + {
1.83 + aLongName[i]=(TText)aCharacterToReplaceWith; // A.B.C becomes A_B.C
1.84 + }
1.85 + alreadyFoundExtensionDelimiter=ETrue;
1.86 + }
1.87 + else
1.88 + {
1.89 + // 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)
1.90 + TBool isSurrogatePair=EFalse;
1.91 +
1.92 + // LAST character in file name or file ext CAN NOT be HIGH surrogate
1.93 + if (i==LongNameLen-1 || i==extDelimiterIndex-1)
1.94 + {
1.95 + if (IsHighSurrogate((TText16)character))
1.96 + {
1.97 + // Corrupt surrogate
1.98 + User::Leave(KErrBadName);
1.99 + }
1.100 + }
1.101 + // FIRST character in file name or file ext CAN NOT be LOW surrogate
1.102 + if (i==0 || i==extDelimiterIndex+1)
1.103 + {
1.104 + if (IsLowSurrogate((TText16)character))
1.105 + {
1.106 + // Corrupt surrogate
1.107 + User::Leave(KErrBadName);
1.108 + }
1.109 + }
1.110 + // if LOW Surrogate
1.111 + if (IsLowSurrogate((TText16)character))
1.112 + {
1.113 + // check for HIGH surrogate
1.114 + if (!IsHighSurrogate(aLongName[--i]))
1.115 + {
1.116 + // Corrupt surrogate
1.117 + User::Leave(KErrBadName);
1.118 + }
1.119 + // surrogate pair found
1.120 + character&=~0xdc00;
1.121 + character|=((aLongName[i]&~0xd800)<<10);
1.122 + character+=0x00010000; // this must be added - it cannot be bitwise-"or"-ed
1.123 + isSurrogatePair=ETrue;
1.124 + }
1.125 +
1.126 + // if High Surrogate
1.127 + if (!isSurrogatePair && IsHighSurrogate((TText16)character))
1.128 + {
1.129 + // Corrupt surrogate
1.130 + User::Leave(KErrBadName);
1.131 + }
1.132 +
1.133 + if (!IsLegalChar(character, EFalse))
1.134 + {
1.135 + if (isSurrogatePair)
1.136 + {
1.137 + aLongName.Delete(i+1, 1);
1.138 + }
1.139 + aLongName[i]=(TText)aCharacterToReplaceWith;
1.140 + }
1.141 + }
1.142 + }
1.143 + }
1.144 +
1.145 +TShortName DoGenerateShortNameL(const TDesC& aLongName,TInt& aNum,TBool aUseTildeSelectively)
1.146 +//
1.147 +// Create a legal shortname from aLongName
1.148 +//
1.149 + {
1.150 +
1.151 + TFileName longName(aLongName);
1.152 + longName.UpperCase();
1.153 + ReplaceIllegalCharactersL(longName, '_');
1.154 + TPtrC longNameWithoutExtension(longName);
1.155 + TPtrC longNameExtension(KNullDesC);
1.156 + const TInt positionOfExtension=longName.LocateReverse(KExtDelimiter);
1.157 + if (positionOfExtension==0)
1.158 + {
1.159 + // No filename specified, so use the extension as the basis of the shortname.
1.160 + // Make sure we always append a tilde+number in this case to avoid generating the same
1.161 + // short filename as one of the protected folders ("\SYS", "\RESOURCE","\PRIVATE")
1.162 + longNameWithoutExtension.Set(longName.Mid(positionOfExtension+1));
1.163 + aUseTildeSelectively = EFalse;
1.164 + if (aNum < 0)
1.165 + aNum = 1;
1.166 + }
1.167 + else if (positionOfExtension!=KErrNotFound)
1.168 + {
1.169 + longNameWithoutExtension.Set(longName.Left(positionOfExtension));
1.170 + longNameExtension.Set(longName.Mid(positionOfExtension+1));
1.171 + }
1.172 +
1.173 + // Converts the original file name main part into 8-bit character string
1.174 + TShortName tempShortName(0);
1.175 +
1.176 + LocaleUtils::ConvertFromUnicodeL(tempShortName, longNameWithoutExtension);
1.177 + const TInt originalNameLength = tempShortName.Length();
1.178 +
1.179 + // Converts the original file name extension part into 8-bit character string
1.180 + TShortName tempShortNameExt(0);
1.181 +
1.182 + LocaleUtils::ConvertFromUnicodeL(tempShortNameExt, longNameExtension);
1.183 + const TInt extensionNameLength = tempShortNameExt.Length();
1.184 + // // const TInt extensionNameLength = tempShortNameExt.Length();
1.185 +
1.186 + // Checks the length of both original file name main part and original file name extension part
1.187 + if(aUseTildeSelectively)
1.188 + {
1.189 + // don't append ~<aNum>
1.190 + if(originalNameLength<=KMaxLengthWithoutTilde && extensionNameLength<=KMaxFatFileNameExt)
1.191 + aNum=-1;
1.192 + }
1.193 +
1.194 + // Applies tilde and number if necessary
1.195 + TBuf8<5> tildeAndNumber;
1.196 + if (aNum>=0)
1.197 + {
1.198 + tildeAndNumber.Append('~');
1.199 + tildeAndNumber.AppendNumUC(aNum,EHex);
1.200 + }
1.201 + const TInt lengthOfTildeAndNumber=tildeAndNumber.Length();
1.202 +
1.203 + // Creates actual shortname from longname of the original file
1.204 + TShortName shortName(11);
1.205 +#if defined(_DEBUG)
1.206 + shortName.Fill(0x01); // fill shortName with garbage to ensure that every byte is written to by this function
1.207 +#endif
1.208 +
1.209 + // Fills the main part of the shortname of the original file
1.210 + const TInt numberOfBytesFreeBeforeTilde=KMaxFatFileNameWithoutExt-lengthOfTildeAndNumber;
1.211 +
1.212 + TPtr8 portionOfShortNameBeforeTilde((TUint8*)shortName.Ptr(), 0, numberOfBytesFreeBeforeTilde);
1.213 + TInt lengthOfPortionOfShortNameBeforeTilde =
1.214 + (originalNameLength < numberOfBytesFreeBeforeTilde) ? originalNameLength : numberOfBytesFreeBeforeTilde;
1.215 +
1.216 + portionOfShortNameBeforeTilde.Copy((TUint8*)tempShortName.Ptr(), lengthOfPortionOfShortNameBeforeTilde);
1.217 + if( lengthOfPortionOfShortNameBeforeTilde != originalNameLength)
1.218 + {
1.219 + for( int i = 0; i<lengthOfPortionOfShortNameBeforeTilde; i++)
1.220 + {
1.221 + if(portionOfShortNameBeforeTilde[i] >= 0x80) //leading byte found
1.222 + {
1.223 + if( i == lengthOfPortionOfShortNameBeforeTilde - 1) //leading byte found on the edge
1.224 + {
1.225 + lengthOfPortionOfShortNameBeforeTilde -= 1;
1.226 + break;
1.227 + }
1.228 + else
1.229 + {
1.230 + i++;
1.231 + }
1.232 + }
1.233 + }
1.234 + }
1.235 + Mem::Copy(((TUint8*)shortName.Ptr())+lengthOfPortionOfShortNameBeforeTilde, tildeAndNumber.Ptr(), lengthOfTildeAndNumber);
1.236 + TInt i;
1.237 + for (i=lengthOfPortionOfShortNameBeforeTilde+lengthOfTildeAndNumber; i<KMaxFatFileNameWithoutExt; ++i)
1.238 + {
1.239 + shortName[i]=' ';
1.240 + }
1.241 +
1.242 + // Fills the extension part of the shortname of the original file
1.243 + TInt lengthOfExt =
1.244 + (extensionNameLength < KMaxFatFileNameExt) ? extensionNameLength : KMaxFatFileNameExt;
1.245 +
1.246 + if( lengthOfExt != extensionNameLength)
1.247 + {
1.248 + for( int i = 0; i<lengthOfExt; i++)
1.249 + {
1.250 + if(tempShortNameExt[i] >= 0x80)
1.251 + {
1.252 + if( i == lengthOfExt - 1)
1.253 + {
1.254 + lengthOfExt -= 1;
1.255 + break;
1.256 + }
1.257 + else
1.258 + {
1.259 + i++;
1.260 + }
1.261 + }
1.262 + }
1.263 + }
1.264 + Mem::Copy(((TUint8*)shortName.Ptr()) + KMaxFatFileNameWithoutExt, tempShortNameExt.Ptr(), lengthOfExt);
1.265 + for (i = KMaxFatFileNameWithoutExt + lengthOfExt; i<KMaxFatFileNameWithoutExt+KMaxFatFileNameExt; ++i)
1.266 + {
1.267 + shortName[i]=' ';
1.268 + }
1.269 +
1.270 + ReplaceFirstCharacterIfClashesWithE5L(shortName);
1.271 + return shortName;
1.272 + }
1.273 +
1.274 +
1.275 +/**
1.276 +Check whether a Dos name is legal or not.
1.277 +
1.278 +@param aName The entry name to be analysed (may be represented as TDes16& or TDes8&)
1.279 +@param anAllowWildCards Flag to indicate whether to allow wildcards in name or not
1.280 +@param aUseExtendedChars Flag to indicate if extended characters are allowed
1.281 +@param aInScanDrive Flag to indicate whether called when scanning drive
1.282 +@param aAllowLowerCase ETrue to allow lower case in the analysed DOS name
1.283 +
1.284 +@return ETrue if the name is a legal DOS one.
1.285 +*/
1.286 +
1.287 +static TBool DoCheckLegalDosName(const TDesC& aName, TBool anAllowWildCards, TBool aUseExtendedChars, TBool aInScanDrive, TBool aAllowLowerCase, TBool aIsForFileCreation)
1.288 + {
1.289 + const TInt count=aName.Length();
1.290 + if (count==0)
1.291 + return EFalse;
1.292 +
1.293 + TInt valid=0;
1.294 + TInt i=0;
1.295 +
1.296 + //-- check the entry name
1.297 + while (i<count)
1.298 + {
1.299 + TChar c=aName[i++];
1.300 + if (c==KExtDelimiter)
1.301 + {
1.302 + // DOS entry names must contain at least one valid character before the extension
1.303 + if (i == 1)
1.304 + return EFalse;
1.305 + break;
1.306 + }
1.307 +
1.308 + if(!aAllowLowerCase && c.IsLower())
1.309 + return EFalse; //-- low case is not allowed
1.310 +
1.311 + if (!IsLegalChar(c,anAllowWildCards,aUseExtendedChars,aInScanDrive))
1.312 + {
1.313 + return EFalse;
1.314 + }
1.315 +
1.316 + if (aIsForFileCreation)
1.317 + {
1.318 + if ((aUseExtendedChars && (TUint) c > KExtendedCharEnd) ||
1.319 + (!aUseExtendedChars && (TUint) c > KExtendedCharStart))
1.320 + {
1.321 + return EFalse;
1.322 + }
1.323 + }
1.324 +
1.325 + if (c!=KMatchAny)
1.326 + if (++valid>KMaxFatFileNameWithoutExt)
1.327 + return EFalse;
1.328 + }
1.329 +
1.330 + //-- check entry extension
1.331 + valid=0;
1.332 + while (i<count)
1.333 + {
1.334 + TChar c=aName[i++];
1.335 + if (c==KExtDelimiter)
1.336 + return EFalse;
1.337 +
1.338 + if(!aAllowLowerCase && c.IsLower())
1.339 + return EFalse; //-- low case is not allowed
1.340 +
1.341 + if (!IsLegalChar(c,anAllowWildCards,aUseExtendedChars,aInScanDrive))
1.342 + return EFalse;
1.343 +
1.344 + if (aIsForFileCreation)
1.345 + {
1.346 + if ((aUseExtendedChars && (TUint) c > KExtendedCharEnd) ||
1.347 + (!aUseExtendedChars && (TUint) c > KExtendedCharStart))
1.348 + {
1.349 + return EFalse;
1.350 + }
1.351 + }
1.352 +
1.353 + if (c!=KMatchAny)
1.354 + if (++valid>KMaxFatFileNameExt)
1.355 + return EFalse;
1.356 + }
1.357 +
1.358 + // Unicode file name checking for file opening.
1.359 + if (!aIsForFileCreation && GetFatUtilityFunctions())
1.360 + {
1.361 + TBuf8<KMaxFileName*2> convertedName8;
1.362 + TRAPD(err, LocaleUtils::ConvertFromUnicodeL(convertedName8, aName, TFatUtilityFunctions::EOverflowActionLeave));
1.363 + if (err != KErrNone)
1.364 + return EFalse;
1.365 +
1.366 + const TInt len8 = convertedName8.Length();
1.367 + TInt j = 0;
1.368 + TInt nonWildChar = 0;
1.369 + while (j < len8)
1.370 + {
1.371 + const TUint8 c8 = convertedName8[j++];
1.372 + if (c8 == KExtDelimiter)
1.373 + break;
1.374 + if (c8 == '*' && !anAllowWildCards)
1.375 + return EFalse;
1.376 + if (c8 == '*' && anAllowWildCards)
1.377 + continue;
1.378 +
1.379 + if (++nonWildChar > KMaxFatFileNameWithoutExt)
1.380 + return EFalse;
1.381 + }
1.382 +
1.383 + // check extension part
1.384 + nonWildChar = 0;
1.385 + while (j < len8)
1.386 + {
1.387 + const TUint8 c8 = convertedName8[j++];
1.388 + if (c8 == KExtDelimiter)
1.389 + return EFalse;
1.390 + if (c8 == '*' && !anAllowWildCards)
1.391 + return EFalse;
1.392 + if (c8 == '*' && anAllowWildCards)
1.393 + continue;
1.394 +
1.395 + if (++nonWildChar > KMaxFatFileNameExt)
1.396 + return EFalse;
1.397 + }
1.398 + }
1.399 +
1.400 + return ETrue;
1.401 + }
1.402 +
1.403 +/**
1.404 + Check whether a Dos name is legal or not. Unicode version
1.405 + parameters and return value absolutely the same as in DoCheckLegalDosName()
1.406 +*/
1.407 +TBool IsLegalDosName(const TDesC16& aName, TBool anAllowWildCards, TBool aUseExtendedChars, TBool aInScanDrive, TBool aAllowLowerCase, TBool aIsForFileCreation)
1.408 + {
1.409 +
1.410 + __PRINT(_L("IsLegalDosName 16"));
1.411 +
1.412 + return DoCheckLegalDosName(aName, anAllowWildCards, aUseExtendedChars, aInScanDrive, aAllowLowerCase, aIsForFileCreation);
1.413 + }
1.414 +
1.415 +TBool CFatMountCB::FindShortNameL(const TShortName& aName,TEntryPos& anEntryPos)
1.416 +//
1.417 +// Returns ETrue and the entryPos of aName if found or EFalse
1.418 +//
1.419 + {
1.420 +
1.421 + __PRINT(_L("VFAT::CFatMountCB::FindShortNameL"));
1.422 + TFatDirEntry fatEntry;
1.423 + TInt count=0;
1.424 + FOREVER
1.425 + {
1.426 + count++;
1.427 + ReadDirEntryL(anEntryPos,fatEntry);
1.428 + MoveToDosEntryL(anEntryPos,fatEntry);
1.429 + if (fatEntry.IsEndOfDirectory())
1.430 + break;
1.431 + if (IsRootDir(anEntryPos)&&(anEntryPos.iPos+StartOfRootDirInBytes()==(RootDirEnd()-KSizeOfFatDirEntry)))
1.432 + if (fatEntry.IsErased())
1.433 + break;//Allows maximum number of entries in root directory
1.434 + if (fatEntry.Name()==aName)
1.435 + return ETrue;
1.436 + MoveToNextEntryL(anEntryPos);
1.437 + if (IsRootDir(anEntryPos)&&(StartOfRootDirInBytes()+anEntryPos.iPos==RootDirEnd()))
1.438 + break;//Allows maximum number of entries in root directory
1.439 + }
1.440 + return EFalse;
1.441 + }
1.442 +
1.443 +TBool CFatMountCB::IsUniqueNameL(const TShortName& aName,TInt aDirCluster)
1.444 +//
1.445 +// Returns ETrue if aName is unique, EFalse if a matching name is found.
1.446 +//
1.447 + {
1.448 +
1.449 + __PRINT(_L("VFAT::CFatMountCB::IsUniqueNameL"));
1.450 + TEntryPos entryPos(aDirCluster,0);
1.451 + if (FindShortNameL(aName,entryPos))
1.452 + return(EFalse);
1.453 + return(ETrue);
1.454 + }
1.455 +
1.456 +void CFatMountCB::ReplaceClashingNameL(const TShortName& aNewName,const TEntryPos& anEntryPos)
1.457 +//
1.458 +// A legal dos name has been typed that clashes with a computer generated shortname
1.459 +// Change the shortname to something else.
1.460 +//
1.461 + {
1.462 +
1.463 + __PRINT(_L("VFAT::CFatMountCB::ReplaceClashingNameL"));
1.464 + TFatDirEntry entry;
1.465 + ReadDirEntryL(anEntryPos,entry);
1.466 + __ASSERT_ALWAYS(entry.IsEndOfDirectory()==EFalse,User::Leave(KErrCorrupt));
1.467 + entry.SetName(aNewName);
1.468 + WriteDirEntryL(anEntryPos,entry);
1.469 +// We now need to fix up VFAT entries with a new checksum reflecting new shortname
1.470 +// Calculate new checksum
1.471 + TUint8 checksum=CalculateShortNameCheckSum(aNewName);
1.472 +// Now go back and adjust all VFAT entries corresponding to this shortname
1.473 + TEntryPos entryPos=anEntryPos;
1.474 + FOREVER
1.475 + {
1.476 + entryPos.iPos-=KSizeOfFatDirEntry;
1.477 + ReadDirEntryL(entryPos,entry);
1.478 + entry.iData[0x0D]=checksum;
1.479 + if (entry.iData[0]&0x40)
1.480 + break;
1.481 + }
1.482 + }
1.483 +
1.484 +TBool CFatMountCB::GenerateShortNameL(TInt aDirCluster,const TDesC& aName,TShortName& aGeneratedName, TBool aForceRandomize)
1.485 +//
1.486 +// Generate a legal dos filename as an alias for aName.
1.487 +// Returns ETrue if aName is a legal dos name.
1.488 +//
1.489 + {
1.490 +
1.491 + __PRINT(_L("VFAT::CFatMountCB::GenerateShortNameL"));
1.492 + // Given the long file-name "ABCDEFGHI.TXT", EPOC used to generate short
1.493 + // file-names in the following pecking order:
1.494 + // "ABCDEFGH.TXT",
1.495 + // "ABCDEF~0.TXT",
1.496 + // "ABCDEF~1.TXT",
1.497 + // "ABCDEF~2.TXT",
1.498 + // etc.
1.499 + // Now, however, EPOC behaves in a more Windows-like manner and
1.500 + // generates short file-names in this pecking order:
1.501 + // "ABCDEF~1.TXT",
1.502 + // "ABCDEF~2.TXT",
1.503 + // "ABCDEF~3.TXT",
1.504 + // "ABCDEF~4.TXT",
1.505 + // After failing to find an unused short name 4 times in a row,
1.506 + // a random number is used to speed up the process. So subsequent
1.507 + // short-file names become
1.508 + // "ABC~nnnn.TXT" where nnnn is a random number
1.509 + //
1.510 + TBool useTildeSelectively = ETrue;
1.511 + TInt endNum = KMaxDuplicateShortName; // 0xFFFF
1.512 + const TInt KMaxNonRandomShortFileNames = 4;
1.513 +
1.514 + TInt i = 1;
1.515 +
1.516 + TBool randomize = aForceRandomize;
1.517 + if (randomize)
1.518 + {
1.519 + i = (TInt) (Math::Random() & KMaxDuplicateShortName);
1.520 + endNum = (i - 1) & KMaxDuplicateShortName;
1.521 + }
1.522 +
1.523 + while(i != endNum)
1.524 + {
1.525 + aGeneratedName=DoGenerateShortNameL(aName,i,useTildeSelectively);
1.526 +
1.527 + if (IsUniqueNameL(aGeneratedName,aDirCluster))
1.528 + break;
1.529 +
1.530 + if (i == KMaxNonRandomShortFileNames && !randomize)
1.531 + {
1.532 + randomize = ETrue;
1.533 + i = (TInt) (Math::Random() & KMaxDuplicateShortName);
1.534 + endNum = (i - 1) & KMaxDuplicateShortName;
1.535 + }
1.536 + else if (i == -1)
1.537 + {
1.538 + useTildeSelectively=EFalse;
1.539 + i = 1;
1.540 + }
1.541 + else
1.542 + i = (i + 1) & KMaxDuplicateShortName;
1.543 + }
1.544 +
1.545 + if (i == endNum)
1.546 + User::Leave(KErrAlreadyExists);
1.547 +
1.548 + if((i == -1) && IsLegalDosName(aName,EFalse,EFalse,EFalse,EFalse,ETrue))
1.549 + {
1.550 + // Original file name is a legal 8.3 name
1.551 + return(ETrue);
1.552 + }
1.553 + else
1.554 + {
1.555 + return(EFalse);
1.556 + }
1.557 +
1.558 +
1.559 + }
1.560 +
1.561 +void TFatDirEntry::InitializeAsVFat(TUint8 aCheckSum)
1.562 +//
1.563 +// Initialize a FAT entry as a VFAT filename
1.564 +//
1.565 + {
1.566 +
1.567 + Mem::Fill(this,sizeof(SFatDirEntry),0xFF);
1.568 + iData[0x0B]=0x0F;
1.569 + iData[0x0C]=0x00; iData[0x0D]=aCheckSum;
1.570 + iData[0x1A]=0x00; iData[0x1B]=0x00;
1.571 + }
1.572 +
1.573 +void TFatDirEntry::SetVFatEntry(const TDesC& aName,TInt aLen)
1.574 +//
1.575 +// Write up to KMaxVFatEntryName unicode chars from aName to the entry
1.576 +//
1.577 + {
1.578 +
1.579 + TInt rem=aName.Length()-aLen;
1.580 + TPtrC section(aName.Ptr()+aLen,Min(rem,KMaxVFatEntryName));
1.581 + TBuf16<KMaxVFatEntryName> buf16;
1.582 + buf16.Copy(section);
1.583 + if (rem<KMaxVFatEntryName)
1.584 + {
1.585 + rem++;
1.586 + buf16.ZeroTerminate();
1.587 + buf16.SetLength(rem); // Zero termination doesn't increase the buf length
1.588 + }
1.589 + TUint8 orderNo=(TUint8)(aLen/KMaxVFatEntryName+1);
1.590 + TInt s=Min(rem,5);
1.591 + Mem::Copy(&iData[0x01],buf16.Ptr(),s*2);//Copy up to 10 bytes of buf16 into iData
1.592 + TInt offset=s;
1.593 + rem-=s;
1.594 + s=Min(rem,6);
1.595 + Mem::Copy(&iData[0x0E],buf16.Ptr()+offset,s*2);
1.596 + offset+=s;
1.597 + rem-=s;
1.598 + s=Min(rem,2);
1.599 + Mem::Copy(&iData[0x1C],buf16.Ptr()+offset,s*2);
1.600 + rem-=s;
1.601 + if (rem==0)
1.602 + orderNo|=0x40;
1.603 + iData[0]=orderNo;
1.604 + }
1.605 +
1.606 +void TFatDirEntry::ReadVFatEntry(TDes16& aBuf) const
1.607 +//
1.608 +// Read KMaxVFatEntryName unicode chars from the entry
1.609 +//
1.610 + {
1.611 +
1.612 + aBuf.SetLength(KMaxVFatEntryName);
1.613 + Mem::Copy(&aBuf[0],&iData[0x01],5*2);
1.614 + Mem::Copy(&aBuf[5],&iData[0x0E],6*2);
1.615 + Mem::Copy(&aBuf[11],&iData[0x1C],2*2);
1.616 + }
1.617 +
1.618 +void CFatMountCB::WriteDirEntryL(TEntryPos& aPos,const TFatDirEntry& aFatDirEntry,const TDesC& aLongName)
1.619 +//
1.620 +// Write a VFAT directory entry to disk at position aPos - leave aPos refering to the dos entry
1.621 +// Assumes sufficient space has been created for it by AddDirEntry.
1.622 +//
1.623 + {
1.624 +
1.625 + __PRINT(_L("VFAT::CFatMountCB::WriteDirEntryL"));
1.626 + __ASSERT_DEBUG(aLongName.Length(),Fault(EVFatNoLongName));
1.627 + TEntryPos startPos(aPos.iCluster,aPos.iPos);
1.628 + TUint8 localBuf[KDefaultSectorSize];
1.629 + TUint8 cksum=CalculateShortNameCheckSum(aFatDirEntry.Name());
1.630 + TInt numEntries=NumberOfVFatEntries(aLongName.Length())-1; // Excluding dos entry
1.631 + // see if all entries written to one sector
1.632 + // single sector writes not supported if sector size>default size
1.633 + TInt dosOffset=numEntries<<KSizeOfFatDirEntryLog2;
1.634 + TInt absolutePos=(aPos.iCluster<<ClusterSizeLog2())+ClusterRelativePos(aPos.iPos);
1.635 + TBool isSameSector=(((absolutePos^(absolutePos+dosOffset))>>SectorSizeLog2())==0 && ((TUint)(1<<SectorSizeLog2())<=KDefaultSectorSize));
1.636 + TFatDirEntry vFatEntry;
1.637 + vFatEntry.InitializeAsVFat(cksum);
1.638 + TInt offset=0;
1.639 + while (numEntries--)
1.640 + {
1.641 + vFatEntry.SetVFatEntry(aLongName,KMaxVFatEntryName*numEntries);// KMaxVFatEntryName=13
1.642 + if(isSameSector)
1.643 + {
1.644 + Mem::Copy(&localBuf[offset],&vFatEntry,KSizeOfFatDirEntry);
1.645 + offset+=KSizeOfFatDirEntry;
1.646 + MoveToNextEntryL(aPos);
1.647 + }
1.648 + else
1.649 + {
1.650 + WriteDirEntryL(aPos,vFatEntry);
1.651 + MoveToNextEntryL(aPos);
1.652 + }
1.653 + }
1.654 + if(isSameSector)
1.655 + {
1.656 + Mem::Copy(&localBuf[offset],&aFatDirEntry,KSizeOfFatDirEntry);
1.657 +
1.658 + //-- use special interface to access FAT directory file
1.659 + DirWriteL(startPos,TPtrC8(&localBuf[0],dosOffset+KSizeOfFatDirEntry));
1.660 + }
1.661 + else
1.662 + WriteDirEntryL(aPos,aFatDirEntry);
1.663 + }
1.664 +
1.665 +void CFatMountCB::EraseDirEntryL(TEntryPos aPos,const TFatDirEntry& aFirstEntry)
1.666 +//
1.667 +// Mark all entries in a VFat directory entry as erased
1.668 +//
1.669 + {
1.670 + __PRINT(_L("VFAT::CFatMountCB::EraseDirEntryL"));
1.671 + TInt numEntries=0;
1.672 + if (aFirstEntry.IsVFatEntry())
1.673 + numEntries=aFirstEntry.NumFollowing();
1.674 + if(IsRuggedFSys()&&numEntries)
1.675 + {
1.676 + TInt count=numEntries;
1.677 + TEntryPos pos=aPos;
1.678 + while(count--)
1.679 + MoveToNextEntryL(pos);
1.680 + EraseDirEntryL(pos);
1.681 + numEntries--;
1.682 + }
1.683 + FOREVER
1.684 + {
1.685 + EraseDirEntryL(aPos);
1.686 + if (!numEntries--)
1.687 + break;
1.688 + MoveToNextEntryL(aPos);
1.689 + }
1.690 + }
1.691 +
1.692 +
1.693 +void LocaleUtils::ConvertFromUnicodeL(TDes8& aForeign, const TDesC16& aUnicode, TFatUtilityFunctions::TOverflowAction aOverflowAction)
1.694 +//
1.695 +// Convert the volume label using the algorithm specified in the current locale-DLL.
1.696 +//
1.697 + {
1.698 + if(aOverflowAction == TFatUtilityFunctions::EOverflowActionLeave)
1.699 + {
1.700 + GetCodePage().ConvertFromUnicodeL(aForeign, aUnicode, TCodePageUtils::EOverflowActionLeave);
1.701 + }
1.702 + else
1.703 + {
1.704 + GetCodePage().ConvertFromUnicodeL(aForeign, aUnicode, TCodePageUtils::EOverflowActionTruncate);
1.705 + }
1.706 + }
1.707 +
1.708 +void LocaleUtils::ConvertToUnicodeL(TDes16& aUnicode, const TDesC8& aForeign, TFatUtilityFunctions::TOverflowAction aOverflowAction)
1.709 +//
1.710 +// Convert the volume label using the algorithm specified in the current locale-DLL.
1.711 +//
1.712 + {
1.713 + if(aOverflowAction == TFatUtilityFunctions::EOverflowActionLeave)
1.714 + {
1.715 + GetCodePage().ConvertToUnicodeL(aUnicode, aForeign, TCodePageUtils::EOverflowActionLeave);
1.716 + }
1.717 + else
1.718 + {
1.719 + GetCodePage().ConvertToUnicodeL(aUnicode, aForeign, TCodePageUtils::EOverflowActionTruncate);
1.720 + }
1.721 + }
1.722 +
1.723 +TBool LocaleUtils::IsLegalShortNameCharacter(TUint aCharacter,TBool aUseExtendedChars)
1.724 +//
1.725 +// Convert the volume label using the algorithm specified in the current locale-DLL.
1.726 +//
1.727 + {
1.728 + return GetCodePage().IsLegalShortNameCharacter(aCharacter, aUseExtendedChars);
1.729 + }